Home Blog SEO
SEO

Shopify Liquid for SEO: useful snippets for themes in 2026

5 Shopify SEO areas live in Liquid, not the admin. Practical snippets for meta tags, JSON-LD, hreflang and Open Graph that scale to thousands of URLs.

Lionel Fenestraz · 1 June 2026 · 10 min read · Updated: June 2026
Code editor showing Liquid snippets in a Shopify theme.liquid file
In this article

Liquid is what separates a Shopify with improvised SEO from one that scales well to thousands of URLs. Shopify’s admin UI only exposes a portion of what the theme controls: title tags, meta descriptions, canonicals, schema.org, hreflang and Open Graph all live in Liquid, not in the dashboard. Touching those files is the difference between a generic theme and an optimised one.

This guide collects the Liquid snippets I use most often when auditing or rewriting the technical SEO of a Shopify store. Each one solves a concrete problem the Shopify UI doesn’t let you fix properly.

In 30 seconds:

  • Liquid is Shopify’s open-source template language, in production use since 2006 and written in Ruby (Shopify Liquid, 2024)
  • 5 key SEO areas depend on Liquid: dynamic meta tags, schema.org, hreflang, Open Graph and custom robots
  • Shopify exposes dozens of Liquid objects (product, collection, shop, page, blog, article, request, canonical_url…) that combine for dynamic SEO (Shopify Liquid Reference, 2025)
  • The theme.liquid file is the most cost-effective to optimise: changes propagate to every URL
  • These snippets require theme code editor access (Online Store > Themes > Edit code) or working on a custom theme

What makes Liquid relevant to SEO?

Liquid is the templating language Shopify uses to render HTML dynamically. When a user opens a product page, Shopify runs the theme with the product object populated and returns static HTML to the browser. For SEO that means every tag Google and AI crawlers read is constructed in Liquid before render.

Unlike other CMSs, Shopify doesn’t have universal SEO plugins. Yoast doesn’t exist here. Shopify SEO apps (SEO Manager, Smart SEO, etc.) are wrappers that inject code into the theme. If you understand Liquid, you don’t need the app, and you almost always get finer control.

The Liquid objects I use most in technical SEO are product, collection, shop, page, request.canonical_url, current_page and localization. Combined with filters like default, escape, strip_html, truncate and image_url, they cover 90% of what you need.


How to generate dynamic title, description and canonical in Liquid

Shopify’s default templates produce generic titles like “Product X – My Store”. That wastes the SERP real estate. The following snippet, placed in the <head> of theme.liquid, generates optimised titles with explicit fallbacks per template:

{% if template contains 'product' %}
  <title>{{ product.title }} – {{ product.vendor }} | {{ shop.name }}</title>
  <meta name="description" content="{{ product.description | strip_html | truncate: 155 }}">
{% elsif template contains 'collection' %}
  <title>{{ collection.title }} | {{ shop.name }}</title>
  <meta name="description" content="{{ collection.description | strip_html | default: collection.title | truncate: 155 }}">
{% elsif template == 'index' %}
  <title>{{ shop.name }} – {{ shop.description }}</title>
  <meta name="description" content="{{ shop.description | truncate: 155 }}">
{% else %}
  <title>{{ page_title }} | {{ shop.name }}</title>
  <meta name="description" content="{{ page_description | default: shop.description | truncate: 155 }}">
{% endif %}

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

Three details that matter here. First, the strip_html filter prevents rich-editor HTML from contaminating the meta description. Second, truncate: 155 keeps the description within SERP limits. Third, {{ canonical_url }} is Shopify’s native variable and automatically respects the primary domain and excluded UTM parameters, so you don’t have to construct it manually.


How to inject JSON-LD at scale with Liquid

Schema.org in Shopify is one of the biggest spots where stores lose enriched search traffic. Most themes include a basic Product schema, but lack BreadcrumbList, FAQ and Organization. The following snippet, inside a {% if template contains 'product' %} block in the head, covers the product case:

{% if template contains 'product' %}
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": {{ product.title | json }},
  "image": {{ product.featured_image | image_url: width: 1200 | prepend: 'https:' | json }},
  "description": {{ product.description | strip_html | json }},
  "sku": {{ product.selected_or_first_available_variant.sku | json }},
  "brand": {
    "@type": "Brand",
    "name": {{ product.vendor | json }}
  },
  "offers": {
    "@type": "Offer",
    "url": {{ shop.url | append: product.url | json }},
    "priceCurrency": {{ shop.currency | json }},
    "price": {{ product.selected_or_first_available_variant.price | money_without_currency | replace: ',', '.' | json }},
    "availability": "{% if product.available %}https://schema.org/InStock{% else %}https://schema.org/OutOfStock{% endif %}"
  }
}
</script>
{% endif %}

What makes this snippet different from Shopify’s default output? The | json filter. It escapes special characters (quotes, line breaks, accents) that would otherwise break the JSON-LD. Without that filter, a description containing a stray quote leaves the schema invalid and Google stops reading it. If you want to go deeper into combining Product, BreadcrumbList and FAQ with the same pattern, I wrote a dedicated guide on schema markup in Shopify.

When schema fails silently. Many stores have malformed schema and don’t know it because the preview in Google’s Rich Results Test looks fine. The frequent error: price with a comma instead of a period ("price": "29,99" breaks, "price": "29.99" works). The replace: ',', '.' filter in the snippet prevents this.


How to handle hreflang in Shopify with Liquid

Shopify Markets produced the biggest multi-language SEO upgrade in years, but the automatic hreflang tags aren’t always right, especially when you have different domains per market. The following snippet in theme.liquid generates dynamic hreflang from the localization object:

{% if localization.available_languages.size > 1 or localization.available_countries.size > 1 %}
  {% for language in localization.available_languages %}
    <link rel="alternate"
          hreflang="{{ language.iso_code }}"
          href="https://{{ shop.domain }}/{{ language.iso_code }}{{ canonical_url | remove_first: shop.url }}">
  {% endfor %}
  <link rel="alternate" hreflang="x-default" href="{{ canonical_url }}">
{% endif %}

Three rules I see violated in every audit of an international Shopify. One: every translated URL must have a bidirectional hreflang (en ↔ es, not just en → es). The for loop solves this. Two: the x-default tag is mandatory if multiple languages exist. Three: the iso_code must be valid (en-GB, en-US, not en-UK or english). Shopify’s language object returns valid codes by default.

If your store uses subdomains or separate domains per market instead of subdirectories, the snippet above won’t work — you need to map each market to its domain in a case/when block. I cover this in more detail in Shopify SEO for ecommerce 2026.


How to configure dynamic Open Graph in Liquid

Facebook, LinkedIn cards and WhatsApp previews depend on Open Graph. Shopify doesn’t generate correct OG by default in older themes. The snippet:

<meta property="og:title" content="{{ page_title | default: shop.name | escape }}">
<meta property="og:description" content="{{ page_description | default: shop.description | escape | truncate: 155 }}">
<meta property="og:url" content="{{ canonical_url }}">
<meta property="og:site_name" content="{{ shop.name | escape }}">
<meta property="og:type" content="{% if template contains 'product' %}product{% elsif template contains 'article' %}article{% else %}website{% endif %}">

{% if template contains 'product' and product.featured_image %}
  <meta property="og:image" content="{{ product.featured_image | image_url: width: 1200 | prepend: 'https:' }}">
  <meta property="og:image:width" content="1200">
  <meta property="og:image:height" content="{{ 1200 | divided_by: product.featured_image.aspect_ratio | round }}">
  <meta property="product:price:amount" content="{{ product.price | money_without_currency }}">
  <meta property="product:price:currency" content="{{ shop.currency }}">
{% elsif settings.share_image %}
  <meta property="og:image" content="{{ settings.share_image | image_url: width: 1200 | prepend: 'https:' }}">
{% endif %}

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ page_title | default: shop.name | escape }}">
<meta name="twitter:description" content="{{ page_description | default: shop.description | escape | truncate: 155 }}">

The escape filter prevents quotes in the title from breaking the HTML. The og:type changes per template, which is what LinkedIn and Facebook expect. The height calculated with aspect_ratio keeps the right proportion without cropping.


What errors in theme.liquid hurt SEO most?

I’ve audited dozens of Shopify stores and the patterns are always the same. The five most costly:

The first is a missing escape filter on meta tags. A single quote in page_title breaks the head HTML, and I’ve seen sites lose rich snippets for months over exactly this. The second: duplicate schema.org, where SEO apps install their own JSON-LD without removing the theme’s, so two Product schemas end up on the same page. Google reads it as ambiguous and stops showing the price in SERP.

  • Canonical pointing to URLs with tracking parameters. The trick: use {{ canonical_url }} (native variable) instead of {{ request.path }} or building it manually. The native variable already excludes UTM parameters.
  • Images without lazy loading or width/height attributes. Liquid can generate both automatically with the image_url filter and width modifiers. Doing so improves Core Web Vitals.
  • And the most costly of all: noindex blocks forgotten in production. A <meta name="robots" content="noindex"> put in during development and never removed is the number-one cause of stores that don’t rank anything after launch. Always look for it on an initial audit — more than once it’s been the only real problem.

If you want a systematic review of the theme code before touching anything, a technical SEO audit for Shopify saves hours of trial and error. Most Liquid problems are caught in under 30 minutes when you know what to look for.


Frequently asked questions

Do I need to know how to code to edit theme.liquid?

Editing .liquid files for SEO doesn’t require being a developer, but it does require knowing basic HTML and understanding Liquid logic ({% if %}, {% for %}, filters). The snippets in this post work by copy-paste, but I always recommend duplicating the theme first (Online Store > Themes > Actions > Duplicate) so you have a rollback if something breaks.

Which theme files do these snippets go in?

Most SEO snippets go in layout/theme.liquid, inside the <head> section. For template-specific schemas, you can create a separate snippet (e.g., snippets/seo-schema.liquid) and call it with {% render 'seo-schema' %} from theme.liquid. For product-specific SEO, the templates/product.liquid or sections/main-product.liquid files are also valid.

Do Shopify SEO apps replace editing Liquid?

Only partially. Apps like SEO Manager or Smart SEO inject code into the theme automatically. They work well for sites without developers, but they limit customisation. If your site has 5,000+ products, advanced schema requirements or international markets with multiple languages, you’ll almost always need to touch Liquid directly.

How do I test that Liquid changes don’t break anything?

Three steps before publishing: (1) use the preview of the duplicated theme, (2) validate the JSON-LD in Google Rich Results Test and Schema.org Validator, and (3) verify the <head> with view-source on a product, collection and homepage. If you have Search Console connected, check the Enhancements section 1-2 weeks later for new errors.

What about Shopify 2.0 and Online Store 2.0 themes?

Online Store 2.0 themes (Dawn, Sense, Refresh, etc.) use modular sections and more accessible metafields. The Liquid logic stays the same; only where you place the code changes. For richer product schemas, Shopify 2.0 metafields let you capture specific attributes (material, ingredients, GTIN) directly from the admin and render them in JSON-LD via Liquid.

How does Liquid SEO differ from WordPress SEO?

Liquid generates HTML on Shopify’s server, no JavaScript plugins. It’s closer to a PHP WordPress theme than to modern Gutenberg. The advantage: SEO renders static and fast. The downside: any change requires theme code editor access or a developer. I compared both approaches in Shopify SEO vs WordPress SEO.


Sources

  1. Shopify. Liquid: Open-source template language. https://shopify.github.io/liquid/. 2024.
  2. Shopify Dev. Liquid objects reference. https://shopify.dev/docs/api/liquid/objects. 2025.
  3. Shopify Dev. Liquid reference (objects, tags, filters). https://shopify.dev/docs/api/liquid. 2025.
  4. Google Search Central. Product structured data documentation. https://developers.google.com/search/docs/appearance/structured-data/product. 2025.
  5. Google Search Central. Tell Google about localized versions of your page. https://developers.google.com/search/docs/specialty/international/localized-versions. 2025.

Is your Shopify not ranking and you don’t know if it’s the theme or the URLs? I offer technical SEO audits for Shopify stores — systematic review of theme code, schema, hreflang and performance. 30-minute free initial call to see if it makes sense.

Lionel Fenestraz — Freelance Google Ads & Meta Ads Consultant
Lionel Fenestraz
Freelance PPC & CRO Consultant · Google Partner · CXL Certified · Google Ads Search Certified
7+ years managing Google Ads and Meta Ads for vacation rental, B2B and ecommerce. Trilingual ES/EN/FR.
Free first call

Could your ad campaigns
perform better?

30 minutes to review your situation and tell you exactly what I would change. No pitch, no sales proposal.

Book a call →
30 min · Google Meet · No commitment