Optimizaciones de theme.liquid para mejorar el SEO en Shopify

Vadim Kravcenko
Vadim Kravcenko
· 9 min read

TL;DR

El archivo theme.liquid de tu tienda Shopify controla la sección <head> de cada página, lo que significa que también controla cómo los motores de búsqueda ven toda tu tienda. Reuní optimizaciones de theme.liquid para mejorar el SEO en Shopify que pueden llevar un tema Dawn de una puntuación de 65 en Lighthouse a 90+. Cada una incluye código Liquid listo para copiar y pegar, una explicación de lo que hace y qué puede salir mal. Tiempo total de implementación: 2-4 horas.

He auditado cientos de tiendas Shopify a través de SEOJuice. El patrón siempre es el mismo: el dueño de la tienda eligió un tema, personalizó los colores, subió productos y nunca volvió a tocar theme.liquid. Mientras tanto, su competidor con los mismos productos y la mitad de backlinks consigue posicionarse por encima en Google porque su desarrollador dedicó una tarde a optimizar el código del tema.

El tema Shopify Dawn obtiene 92 en PageSpeed recién instalado: es el tema gratuito más rápido disponible en Shopify. Pero incluso tal como viene, todavía deja varias oportunidades SEO importantes sin aprovechar. Faltan datos estructurados. La carga de fuentes no está optimizada. No hay sugerencias de conexión previa (preconnect). Las etiquetas OG están incompletas.

Esta guía corrige todo eso. Y la siguiente sección —etiquetas canonical— es la que me gustaría que todos los dueños de tiendas Shopify entendieran antes de llegar preguntándome por qué Google estaba indexando la versión equivocada de sus páginas de producto.

¿Qué es theme.liquid?

Si no eres desarrollador, aquí va la versión de 30 segundos: theme.liquid es el archivo de plantilla maestro que envuelve absolutamente todas las páginas de tu tienda Shopify. Define la estructura de <html>, <head> y <body>. Cada página de producto, página de colección, artículo del blog y página de inicio hereda de este archivo.

Cuando agregas algo a la sección <head> de theme.liquid, aparece en todas las páginas. Eso lo convierte en el lugar perfecto para:

  • Metaetiquetas para toda la tienda (valores OG por defecto, Twitter Cards)
  • Datos estructurados de tu organización
  • Indicaciones de carga de recursos (preload, preconnect) para rendimiento
  • Lógica de etiquetas canonical
  • Optimización de carga de fuentes

Para editarlo: Shopify Admin → Online Store → Themes → Edit Code → Layout → theme.liquid

Conclusión clave

Duplica siempre tu tema antes de editarlo. Ve a Online Store → Themes → Actions → Duplicate. Trabaja sobre la copia. Si algo se rompe, puedes volver atrás al instante.

Tabla de referencia rápida

Aquí tienes qué vamos a implementar, dónde va y qué impacto puede tener:

Optimización Dónde agregarla Impacto SEO Dificultad
Etiquetas canonical theme.liquid <head> Alto — evita contenido duplicado Fácil
Datos estructurados de organización theme.liquid <head> Medio — panel de conocimiento de marca Fácil
Datos estructurados de producto product.liquid o sección Alto — resultados enriquecidos en SERP Media
Datos estructurados de breadcrumbs Snippet + plantilla Medio — breadcrumbs en SERP Media
Precarga de fuentes theme.liquid <head> Alto — mejora de LCP Fácil
CSS crítico en línea theme.liquid <head> Alto — elimina bloqueo de renderizado Difícil
Diferir JavaScript no crítico theme.liquid al final de <body> Alto — procesamiento del DOM más rápido Media
Metaetiquetas OG/Twitter theme.liquid <head> Medio — compartidos en redes sociales Fácil
Etiquetas hreflang theme.liquid <head> Alto — SEO internacional Media
Lazy loading de imágenes Plantillas/secciones Medio — reduce la carga inicial Fácil

1. Etiquetas canonical en theme.liquid para evitar duplicados

Shopify genera muchas URL duplicadas. Se puede acceder a un producto desde /products/widget y /collections/sale/products/widget: mismo producto, dos URL. Sin una etiqueta canonical, Google ve contenido duplicado y puede indexar la URL equivocada. He visto tiendas donde Google indexó la URL con ruta de colección para absolutamente todos los productos, lo que significaba que las URL “reales” del producto no acumulaban autoridad.

Dawn incluye un manejo básico de canonical, pero vale la pena verificarlo y mejorarlo. Agrega esto a tu sección <head> en theme.liquid:

{%- liquid
  assign canonical_url = canonical_url | default: request.origin | append: request.path
-%}

<link rel="canonical" href="{{ canonical_url }}">

{%- if paginate and paginate.pages > 1 -%}
  {%- if paginate.previous -%}
    <link rel="prev" href="{{ paginate.previous.url }}">
  {%- endif -%}
  {%- if paginate.next -%}
    <link rel="next" href="{{ paginate.next.url }}">
  {%- endif -%}
{%- endif -%}

Esto hace tres cosas: establece la URL canonical usando la variable integrada canonical_url de Shopify (que resuelve la URL correcta para productos sin importar cómo se acceda a ellos), agrega rel="prev"/rel="next" para colecciones paginadas y usa como fallback el origen de la solicitud + la ruta si canonical_url no está disponible.

Conclusión clave

Verifica que tu tema no esté generando ya una etiqueta canonical antes de agregar esto. Las etiquetas canonical duplicadas confunden más a los motores de búsqueda que no tener ninguna. Primero busca “canonical” en tu archivo theme.liquid.

2. Datos estructurados de organización (JSON-LD) para reforzar tu marca

Los datos estructurados de organización le dicen a Google quién eres: nombre de tu negocio, logo, perfiles sociales e información de contacto. Esto es lo que alimenta el panel de conocimiento que aparece cuando alguien busca tu marca. He visto tiendas pasar de no tener ningún panel de conocimiento a tener uno completo en tres semanas después de agregar este marcado correctamente.

Agrega esto dentro de <head> en theme.liquid. Se incluye en todas las páginas, que es exactamente lo que Google quiere:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": {{ shop.name | json }},
  "url": "{{ shop.url }}",
  {%- if shop.brand.logo -%}
  "logo": {{ shop.brand.logo | image_url: width: 600 | json }},
  {%- endif -%}
  "description": {{ shop.description | json }},
  "address": {
    "@type": "PostalAddress",
    "addressCountry": {{ shop.address.country | json }}
  }
  {%- if shop.brand.social_links.size > 0 -%}
  ,"sameAs": [
    {%- for link in shop.brand.social_links -%}
      {{ link | json }}{%- unless forloop.last -%},{%- endunless -%}
    {%- endfor -%}
  ]
  {%- endif -%}
}
</script>

Fíjate que estoy usando el filtro | json en lugar de | escape. Esto importa mucho: json escapa correctamente las cadenas para el contexto JSON-LD, incluyendo las comillas. Usar escape en JSON-LD es un error común que produce marcado inválido. He depurado este problema específico en al menos una docena de tiendas de clientes: los datos estructurados validan en la herramienta de pruebas de Google, pero fallan silenciosamente en producción porque el escape está mal hecho.

"JSON-LD es el formato preferido por Google para datos estructurados. Si vas a implementar marcado Schema.org en Shopify, elige siempre JSON-LD por encima de microdata: es más limpio, más fácil de depurar y no se mezcla con tu HTML de presentación."

— Greg Bernhardt, Senior SEO Strategist en Shopify (fuente)

3. Datos estructurados de producto para conseguir resultados enriquecidos

Los datos estructurados de producto son lo que te consiguen esos resultados enriquecidos en Google: estrellas, precio, estado de disponibilidad. Dawn incluye datos estructurados de producto básicos, pero muchas veces están incompletos. Aquí tienes una versión más completa que he ido afinando con pruebas en decenas de tiendas.

Crea un snippet nuevo: snippets/json-ld-product.liquid

{%- if product -%}
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": {{ product.title | json }},
  "url": "{{ shop.url }}{{ product.url }}",
  "description": {{ product.description | strip_html | truncate: 500 | json }},
  {%- if product.featured_image -%}
  "image": [
    {{ product.featured_image | image_url: width: 1200 | json }}
    {%- for image in product.images offset: 1 limit: 4 -%}
    ,{{ image | image_url: width: 1200 | json }}
    {%- endfor -%}
  ],
  {%- endif -%}
  "brand": {
    "@type": "Brand",
    "name": {{ product.vendor | json }}
  },
  {%- if product.selected_or_first_available_variant.sku != blank -%}
  "sku": {{ product.selected_or_first_available_variant.sku | json }},
  {%- endif -%}
  {%- if product.selected_or_first_available_variant.barcode != blank -%}
  "gtin": {{ product.selected_or_first_available_variant.barcode | json }},
  {%- endif -%}
  "offers": {
    "@type": "AggregateOffer",
    "priceCurrency": {{ cart.currency.iso_code | json }},
    "lowPrice": {{ product.price_min | money_without_currency | json }},
    "highPrice": {{ product.price_max | money_without_currency | json }},
    "offerCount": {{ product.variants.size }},
    "availability": "https://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}",
    "url": "{{ shop.url }}{{ product.url }}"
  }
  {%- if product.metafields.reviews.rating.value != blank -%}
  ,"aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": {{ product.metafields.reviews.rating.value | json }},
    "reviewCount": {{ product.metafields.reviews.rating_count.value | json }}
  }
  {%- endif -%}
}
</script>
{%- endif -%}

Luego inclúyelo en tu plantilla de producto (normalmente sections/main-product.liquid o templates/product.liquid):

{% render 'json-ld-product' %}

Detalles importantes: estoy usando AggregateOffer en vez de objetos Offer individuales porque queda más limpio para productos con múltiples variantes. Los campos de rating usan los metafields nativos de reseñas de producto de Shopify; si usas una app de reseñas de terceros, tendrás que ajustar el namespace del metafield. (Judge.me y Loox usan namespaces distintos; revisa su documentación antes de copiar esto tal cual.)

4. Datos estructurados de breadcrumbs para mejorar la lectura de la SERP

Los breadcrumbs ayudan a Google a entender la jerarquía de tu sitio y pueden aparecer directamente en los resultados de búsqueda, reemplazando la URL cruda. Esto es especialmente valioso para tiendas con estructuras de categorías profundas. En una tienda que audité, agregar datos estructurados de breadcrumbs cambió la visualización en la SERP de example.com › collections › summer-2025 › products › red-dress a un limpio Inicio > Colección de verano > Vestido rojo, lo que mejoró de forma medible el CTR.

Crea snippets/json-ld-breadcrumbs.liquid:

{%- assign breadcrumb_list = "" | split: "" -%}

{%- if template.name == 'product' -%}
  {%- if product.collections.size > 0 -%}
    {%- assign primary_collection = product.collections | first -%}
    {%- capture crumb_collection -%}{"name":{{ primary_collection.title | json }},"url":"{{ shop.url }}{{ primary_collection.url }}"}{%- endcapture -%}
    {%- assign breadcrumb_list = breadcrumb_list | push: crumb_collection -%}
  {%- endif -%}
  {%- capture crumb_product -%}{"name":{{ product.title | json }},"url":"{{ shop.url }}{{ product.url }}"}{%- endcapture -%}
  {%- assign breadcrumb_list = breadcrumb_list | push: crumb_product -%}

{%- elsif template.name == 'collection' -%}
  {%- capture crumb_coll -%}{"name":{{ collection.title | json }},"url":"{{ shop.url }}{{ collection.url }}"}{%- endcapture -%}
  {%- assign breadcrumb_list = breadcrumb_list | push: crumb_coll -%}

{%- elsif template.name == 'article' -%}
  {%- capture crumb_blog -%}{"name":{{ blog.title | json }},"url":"{{ shop.url }}{{ blog.url }}"}{%- endcapture -%}
  {%- assign breadcrumb_list = breadcrumb_list | push: crumb_blog -%}
  {%- capture crumb_article -%}{"name":{{ article.title | json }},"url":"{{ shop.url }}{{ article.url }}"}{%- endcapture -%}
  {%- assign breadcrumb_list = breadcrumb_list | push: crumb_article -%}
{%- endif -%}

{%- if breadcrumb_list.size > 0 -%}
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "{{ shop.url }}"
    }
    {%- for crumb_json in breadcrumb_list -%}
    ,{
      "@type": "ListItem",
      "position": {{ forloop.index | plus: 1 }},
      "name": {{ crumb_json | split: '"name":' | last | split: ',"url"' | first }},
      "item": {{ crumb_json | split: '"url":' | last | split: '}' | first }}
    }
    {%- endfor -%}
  ]
}
</script>
{%- endif -%}

Agrega {% render 'json-ld-breadcrumbs' %} en tu theme.liquid justo antes de </head>. El snippet detecta automáticamente el tipo de página y construye la cadena de breadcrumbs adecuada.

5. Precarga de fuentes y preconnect para acelerar el SEO en Shopify

Este siguiente cambio es el que marcó la mayor diferencia en nuestras tiendas de prueba. Solo la precarga de fuentes puede recortar un segundo completo del tiempo hasta que aparece el texto, y en e-commerce ese segundo se correlaciona directamente con la tasa de rebote. El propio equipo de ingeniería de Shopify mostró el impacto en shopify.com:

"Con preload, los desarrolladores front-end pueden indicarle al navegador que descargue los archivos de fuentes necesarios al mismo tiempo que los archivos CSS. Solo 17 líneas de código redujeron en 50% el tiempo para mostrar texto en shopify.com."

— Colin Bendell, Shopify Engineering (fuente)

El problema: los navegadores no pueden descargar fuentes hasta haber procesado tanto el HTML como el CSS que las referencia. Eso son dos viajes secuenciales antes de que aparezca el texto. Preload le dice al navegador: “empieza a descargar esta fuente ahora, la vas a necesitar en breve”.

Agrega esto cerca de la parte superior de <head> en theme.liquid, antes de tus etiquetas de stylesheet:

{%- comment -%}
  Preload your primary heading and body fonts.
  Check your theme's font settings to get the correct filenames.
  Use font-display: swap in your CSS to prevent FOIT (Flash of Invisible Text).
{%- endcomment -%}

{%- if settings.type_header_font != blank -%}
  <link rel="preload"
        href="{{ settings.type_header_font | font_url }}"
        as="font"
        type="font/woff2"
        crossorigin>
{%- endif -%}

{%- if settings.type_body_font != blank -%}
  <link rel="preload"
        href="{{ settings.type_body_font | font_url }}"
        as="font"
        type="font/woff2"
        crossorigin>
{%- endif -%}

{%- comment -%} Preconnect to Shopify's CDN for faster asset loading {%- endcomment -%}
<link rel="preconnect" href="https://cdn.shopify.com" crossorigin>
<link rel="preconnect" href="https://fonts.shopifycdn.com" crossorigin>

El atributo crossorigin es obligatorio para precargas de fuentes; sin él, el navegador descarga la fuente dos veces. He visto exactamente este error en tiendas en producción, donde eliminar la descarga duplicada por sí sola mejoró el LCP en 400ms. Las indicaciones de preconnect ahorran otros ~100ms al establecer antes la conexión TCP + TLS con el CDN de Shopify.

Conclusión clave

Precarga solo las fuentes que usas above the fold. Cada preload compite por ancho de banda. Si precargas cinco fuentes, arruinaste el objetivo: el navegador descargará las cinco en paralelo y ralentizará todo lo demás.

6. CSS crítico en línea para reducir bloqueo de renderizado

El CSS que bloquea el renderizado es la razón #1 por la que las tiendas Shopify puntúan mal en Lighthouse. El navegador no puede pintar nada hasta descargar y procesar toda tu hoja de estilos, incluso el CSS del footer que está 3,000px por debajo del fold. Esta es la optimización más difícil de la lista, pero también la que más consistentemente entrega la mayor mejora en Lighthouse de todas las auditorías que he hecho.

La solución: insertar en línea el CSS necesario para el contenido above the fold directamente en <head> y cargar el resto de forma asíncrona.

{%- comment -%}
  Step 1: Inline critical CSS directly in the head.
  Generate your critical CSS using a tool like our
  Critical CSS Generator at /tools/critical-css-generator/
  Then paste it into a snippet: snippets/critical-css.liquid
{%- endcomment -%}

<style>
  {% render 'critical-css' %}
</style>

{%- comment -%}
  Step 2: Load full stylesheet asynchronously using the media trick.
  The browser treats media="print" as non-render-blocking,
  then onload switches it to media="all" so styles apply.
{%- endcomment -%}

<link rel="stylesheet"
      href="{{ 'base.css' | asset_url }}"
      media="print"
      onload="this.media='all'">

<noscript>
  <link rel="stylesheet" href="{{ 'base.css' | asset_url }}">
</noscript>

Como alternativa, Shopify ofrece el filtro Liquid inline_asset_content, que puede insertar CSS directamente desde tus archivos de assets, eliminando la necesidad de un snippet separado:

<style>{{ 'critical.css' | asset_url | inline_asset_content }}</style>

Generar CSS crítico correctamente requiere analizar cada plantilla. Recomiendo usar una herramienta generadora de CSS crítico: extrae exactamente las reglas CSS necesarias para el contenido above the fold en cada tipo de página. Si esto sale mal (por ejemplo, si falta una regla para tu hero), tendrás un flash de contenido sin estilos que es peor que no optimizar nada.

7. Diferir JavaScript no crítico en theme.liquid

Los scripts que bloquean el parser son el segundo mayor asesino del rendimiento después del CSS que bloquea el renderizado. La guía oficial de Shopify es clara: tu bundle JS minificado debería pesar 16KB o menos, y todo lo demás debería diferirse.

En theme.liquid, busca tus etiquetas <script> y agrega defer:

{%- comment -%}
  WRONG — blocks DOM parsing:
  {{ 'theme.js' | asset_url | script_tag }}

  RIGHT — deferred loading:
{%- endcomment -%}

<script src="{{ 'theme.js' | asset_url }}" defer></script>

{%- comment -%}
  For third-party scripts (analytics, chat widgets, etc.),
  load them after the page is interactive:
{%- endcomment -%}

<script>
  // Load non-essential scripts after user interaction
  function loadDeferredScripts() {
    // Example: chat widget, analytics, etc.
    var scripts = [
      '{{ "deferred-features.js" | asset_url }}'
    ];
    scripts.forEach(function(src) {
      var s = document.createElement('script');
      s.src = src;
      s.defer = true;
      document.body.appendChild(s);
    });
  }

  // Trigger on first user interaction
  ['click', 'scroll', 'keydown', 'touchstart'].forEach(function(evt) {
    window.addEventListener(evt, function handler() {
      loadDeferredScripts();
      ['click', 'scroll', 'keydown', 'touchstart'].forEach(function(e) {
        window.removeEventListener(e, handler);
      });
    }, { once: true, passive: true });
  });
</script>

El patrón de carga basado en interacción es agresivo, pero funciona. Widgets de chat, popups de reseñas y funciones parecidas no necesitan cargarse hasta que el usuario realmente haga algo en la página. En una tienda que probamos, este patrón recortó 340ms del Time to Interactive, y esa fue la diferencia entre una puntuación INP de “needs improvement” y una “good” en datos de CrUX.

8. Metaetiquetas OG/Twitter para compartir productos correctamente

Cuando alguien comparte tu producto en Facebook, Twitter o LinkedIn, las etiquetas OG (Open Graph) controlan lo que aparece en la vista previa. Sin ellas, las plataformas sociales adivinan, y adivinan fatal. He visto compartidos de productos que mostraban el favicon de la tienda como imagen y el título de la página de checkout como descripción.

Dawn incluye un snippet social-meta-tags.liquid, pero muchas veces es mínimo. Aquí tienes una versión más completa. Crea o actualiza snippets/social-meta-tags.liquid:

{%- liquid
  assign og_title = page_title | default: shop.name
  assign og_description = page_description | default: shop.description | strip_html | truncate: 200
  assign og_url = canonical_url | default: request.origin | append: request.path
  assign og_type = 'website'
  assign og_image = ''
-%}

{%- if template.name == 'product' -%}
  {%- assign og_type = 'product' -%}
  {%- if product.featured_image -%}
    {%- assign og_image = product.featured_image | image_url: width: 1200, height: 630 -%}
  {%- endif -%}
{%- elsif template.name == 'article' -%}
  {%- assign og_type = 'article' -%}
  {%- if article.image -%}
    {%- assign og_image = article.image | image_url: width: 1200, height: 630 -%}
  {%- endif -%}
{%- elsif template.name == 'collection' -%}
  {%- if collection.image -%}
    {%- assign og_image = collection.image | image_url: width: 1200, height: 630 -%}
  {%- endif -%}
{%- endif -%}

{%- if og_image == blank and shop.brand.cover_image -%}
  {%- assign og_image = shop.brand.cover_image | image_url: width: 1200, height: 630 -%}
{%- endif -%}

<!-- Open Graph -->
<meta property="og:site_name" content="{{ shop.name }}">
<meta property="og:title" content="{{ og_title }}">
<meta property="og:description" content="{{ og_description }}">
<meta property="og:url" content="{{ og_url }}">
<meta property="og:type" content="{{ og_type }}">
{%- if og_image != blank -%}
<meta property="og:image" content="{{ og_image }}">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
{%- endif -%}

{%- if template.name == 'product' -%}
<meta property="product:price:amount" content="{{ product.price | money_without_currency }}">
<meta property="product:price:currency" content="{{ cart.currency.iso_code }}">
{%- endif -%}

<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ og_title }}">
<meta name="twitter:description" content="{{ og_description }}">
{%- if og_image != blank -%}
<meta name="twitter:image" content="{{ og_image }}">
{%- endif -%}

Inclúyelo en theme.liquid con {% render 'social-meta-tags' %} dentro de <head>. Las dimensiones de imagen 1200x630 están optimizadas tanto para Facebook como para el formato de tarjeta grande de Twitter/X.

9. Etiquetas hreflang para SEO internacional en Shopify

Si vendes en varios países o idiomas, las etiquetas hreflang le dicen a Google qué versión de una página debe mostrar a cada audiencia. Sin ellas, tu tienda en francés podría aparecer en resultados de búsqueda en alemán, y sí, he visto exactamente eso pasarle a un cliente que estuvo recibiendo tickets de soporte en el idioma equivocado durante meses antes de descubrir la causa.

Shopify Markets genera automáticamente etiquetas hreflang para dominios internacionales y subcarpetas. Pero si necesitas control personalizado, o si usas una app de traducción, agrega esto al <head> de theme.liquid:

{%- if request.locale and localization.available_languages.size > 1 -%}
  {%- for locale in localization.available_languages -%}
    {%- if locale.primary -%}
      {%- assign locale_root = shop.url -%}
    {%- else -%}
      {%- assign locale_root = shop.url | append: '/' | append: locale.iso_code -%}
    {%- endif -%}

    <link rel="alternate"
          hreflang="{{ locale.iso_code }}"
          href="{{ locale_root }}{{ request.path }}">
  {%- endfor -%}

  {%- comment -%} x-default points to your primary language {%- endcomment -%}
  <link rel="alternate"
        hreflang="x-default"
        href="{{ shop.url }}{{ request.path }}">
{%- endif -%}

La etiqueta x-default es crítica: le dice a Google qué versión mostrar cuando ninguno de los idiomas especificados coincide con la preferencia del usuario. Apúntala siempre a tu mercado principal.

10. Lazy loading de imágenes sin dañar el LCP

El lazy loading nativo ya es compatible con 92% de los navegadores. El filtro Liquid image_tag de Shopify lo maneja automáticamente: las imágenes después de las primeras tres secciones reciben loading="lazy" por defecto.

Pero tienes que asegurarte de no aplicar lazy loading a las imágenes above the fold, que es un error muy común y que en realidad empeora el LCP. El mes pasado audité una tienda que tenía loading="lazy" en su banner hero: estaba agregando 800ms a su LCP porque el navegador estaba despriorizando la imagen más importante de la página:

{%- comment -%}
  Hero image — above the fold, NEVER lazy load.
  Use loading: 'eager' and fetchpriority: 'high' to prioritize it.
{%- endcomment -%}

{{ section.settings.hero_image
  | image_url: width: 1920
  | image_tag:
    loading: 'eager',
    fetchpriority: 'high',
    sizes: '100vw',
    widths: '375, 750, 1100, 1500, 1920'
}}

{%- comment -%}
  Product images below the fold — let Shopify's default lazy loading work.
  Don't set loading attribute; Shopify handles it via section.index.
{%- endcomment -%}

{{ product.featured_image
  | image_url: width: 800
  | image_tag:
    sizes: '(min-width: 750px) 50vw, 100vw',
    widths: '375, 750, 800'
}}

El atributo fetchpriority: 'high' en tu imagen LCP es una incorporación más reciente que le dice al navegador que priorice esta imagen por encima de otros recursos. Combinado con no aplicarle lazy loading, es probablemente la acción individual más impactante que puedes tomar para mejorar tu puntuación de LCP.

Cómo depurar tus cambios en theme.liquid

Panel de rendimiento web de Shopify mostrando puntuaciones de Core Web Vitals a lo largo del tiempo con anotaciones de eventos
El panel integrado de rendimiento web de Shopify rastrea cómo los cambios en el tema afectan los Core Web Vitals con el tiempo. Fuente: Shopify Performance Blog

Ya hiciste los cambios. Ahora verifica que realmente funcionen. (He visto desarrolladores saltarse este paso y descubrir tres meses después que sus datos estructurados eran inválidos todo el tiempo.)

Paso 1: valida los datos estructurados. Ve a la prueba de resultados enriquecidos de Google e introduce la URL de tu producto. Cada tipo de datos estructurados que agregaste debería aparecer con una marca verde. Errores comunes: comas faltantes en arrays JSON-LD, comillas sin escapar en descripciones de producto y URL de imágenes inválidas.

Paso 2: revisa las etiquetas canonical. Abre el código fuente de la página (Ctrl+U) y busca “canonical”. Deberías ver exactamente una etiqueta canonical por página. Si ves dos, tu tema ya estaba agregando una: elimina el duplicado.

Paso 3: ejecuta Lighthouse. Abre Chrome DevTools → Lighthouse → marca Performance y SEO → Generate Report. Compara tus puntuaciones antes y después. Guarda capturas de pantalla: vas a querer esa comparación cuando un cliente te pregunte qué hiciste exactamente.

Paso 4: prueba las vistas previas sociales. Usa Facebook's Sharing Debugger y Twitter's Card Validator para previsualizar cómo se ven tus páginas de producto cuando se comparten.

Errores comunes que te van a morder después:

  • JSON-LD inválido — usa jsonlint.com para validar tu JSON antes de desplegar. La salida de plantillas Liquid puede producir comas finales o llaves faltantes.
  • Etiquetas duplicadas — si tu tema ya tiene etiquetas OG, agregar más crea duplicados. Elimina las originales o sobrescríbelas.
  • Precargar demasiados recursos — los navegadores solo manejan 6 conexiones concurrentes por dominio. Si precargas 8 cosas, estás perjudicando el rendimiento, no ayudándolo.
  • Archivo de fuente incorrecto en preload — si precargas una fuente woff2 pero tu CSS referencia una fuente woff, el navegador descargará ambas. Haz coincidir el formato exactamente.

Impacto en rendimiento de estas optimizaciones SEO en Shopify

Resultados de auditoría de Google Lighthouse mostrando puntuaciones de rendimiento, accesibilidad, buenas prácticas y SEO para una tienda Shopify
Puntuaciones de Google Lighthouse para una tienda Shopify. Las optimizaciones de theme.liquid, como JavaScript diferido y precarga de recursos críticos, mejoran directamente estos números. Fuente: Shopify Enterprise Blog

Esto es lo que puedes esperar de forma realista de cada optimización, según auditorías que he hecho en tiendas basadas en Dawn:

Optimización Cambio esperado en LCP Cambio esperado en CLS Puntos en Lighthouse
Precarga de fuentes -300ms a -1.2s Sin cambios +3 a +8
CSS crítico en línea -200ms a -800ms -0.02 a -0.05 +5 a +15
Diferir JavaScript no crítico -100ms a -500ms Sin cambios +3 a +10
Lazy loading de imágenes (bien hecho) -100ms a -400ms Ligera mejora +2 a +5
Datos estructurados (todos los tipos) Sin cambios Sin cambios +2 a +5 (puntuación SEO)
Canonical + hreflang Sin cambios Sin cambios +1 a +3 (puntuación SEO)
Total combinado -0.7s a -2.9s -0.02 a -0.05 +15 a +35

Estos números varían bastante según tu punto de partida. Una tienda que ya puntúa 85+ en Lighthouse verá mejoras menores que una que puntúa 55. La precarga de fuentes y el CSS crítico son, de forma consistente, los cambios que más impacto tienen. Si vas corto de tiempo, empieza por esos dos.

FAQ

¿Estos cambios sobreviven a una actualización del tema?

Si estás editando el código del tema directamente, no. Las actualizaciones del tema sobrescribirán tus cambios. Por eso recomiendo usar snippets (json-ld-product.liquid, social-meta-tags.liquid, etc.) siempre que sea posible. Los snippets sobreviven a algunas actualizaciones. Para máxima seguridad, documenta cada cambio que hagas y vuelve a aplicarlo después de actualizar, o usa un flujo de control de versiones con Shopify CLI.

¿Puedo usar una app de Shopify en lugar de editar código?

Sí, apps como JSON-LD for SEO y Smart SEO manejan datos estructurados sin cambios de código. El intercambio es este: las apps añaden sobrecarga de JavaScript (irónico para una optimización de rendimiento), cuestan $5-20/mes y te dan menos control. Para precarga de fuentes y CSS crítico, no hay sustituto real para los cambios a nivel de código.

¿Esto funciona con temas distintos de Dawn?

Los datos estructurados, las etiquetas OG y el código hreflang funcionan con cualquier tema Shopify. La sintaxis de precarga de fuentes puede variar: revisa el settings_schema.json de tu tema para encontrar los nombres correctos de las variables de fuente. El CSS crítico, por definición, depende del tema. Los patrones de código Liquid son universales en los temas Online Store 2.0.

¿Cómo sé si mis datos estructurados están funcionando?

Usa la prueba de resultados enriquecidos de Google (search.google.com/test/rich-results) para URL individuales. Para validación a nivel de sitio, revisa Google Search Console → Mejoras. Google puede tardar 2-4 semanas en procesar nuevos datos estructurados y mostrar resultados en el informe de Mejoras.

¿Cuál es la diferencia entre defer y async en las etiquetas script?

defer descarga el script en paralelo, pero espera a ejecutarlo hasta que el HTML esté completamente procesado. async descarga en paralelo y se ejecuta inmediatamente cuando está listo, lo que puede interrumpir el procesamiento del HTML. Para scripts del tema, usa siempre defer. Usa async solo para scripts realmente independientes, como analytics, que no interactúan con el DOM.

Qué sigue

Estas optimizaciones de theme.liquid para mejorar el SEO en Shopify cubren los cambios de mayor impacto que puedes hacer en theme.liquid. Pero el SEO es más que código. Tus descripciones de producto, enlazado interno, textos alt de imágenes y estrategia de contenidos importan igual.

Si quieres profundizar:

SEOJuice
Stay visible everywhere
Get discovered across Google and AI platforms with research-based optimizations.
Works with any CMS
Automated Internal Links
On-Page SEO Optimizations
Get Started Free

no credit card required

More articles

No related articles found.