How to add dynamic breadcrumb schema in Shopify requires inserting JSON-LD structured data that pulls navigation paths automatically from Shopify’s template variables. This guide from HiAgency covers implementation for product pages, collection pages, and blog posts using Liquid code that adapts to your site structure without manual updates.

What Makes Breadcrumb Schema Dynamic in Shopify?
Dynamic breadcrumb schema generates navigation paths automatically from Shopify’s database using Liquid template variables. Static breadcrumbs require hardcoding each URL and title, breaking when you rename collections or move products between categories.
Dynamic implementation benefits:- Automatic updates – Schema reflects current collection names and product locations without code changes
- Multi-level support – Handles nested collections (Department > Category > Subcategory) automatically
- Template flexibility – Works across different page types (products, collections, pages, blogs) with single implementation
- Maintenance-free – No manual edits needed when restructuring site navigation
How to Add Dynamic Breadcrumb Schema for Product Pages
Product page breadcrumbs show the path from homepage through collection to the specific product. Implementation uses the product’s collection assignment to build the hierarchy.
Step 1: Access Product Template File
Navigate to theme code editor:- Go to Online Store > Themes
- Click Actions > Edit code
- Open Templates/product.liquid (or sections/main-product.liquid for OS 2.0 themes)
Step 2: Insert Dynamic Product Breadcrumb Schema
Add this code near the closing </body> tag or in the template head:<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{ shop.url }}"
},
{% if product.collections.size > 0 %}
{
"@type": "ListItem",
"position": 2,
"name": "{{ product.collections.first.title }}",
"item": "{{ shop.url }}{{ product.collections.first.url }}"
},
{% endif %}
{
"@type": "ListItem",
"position": {% if product.collections.size > 0 %}3{% else %}2{% endif %},
"name": "{{ product.title }}",
"item": "{{ shop.url }}{{ product.url }}"
}
]
}
</script>This code creates a three-level breadcrumb: Home > Collection > Product. The {% if %} conditional handles products not assigned to collections.Step 3: Handle Multiple Collection Assignments
Products assigned to multiple collections need logic to select the most relevant collection for breadcrumbs:{% assign current_collection = collection %}
{% if current_collection == blank and product.collections.size > 0 %}
{% assign current_collection = product.collections.first %}
{% endif %}Add this before the schema block. It prioritizes the collection from which the customer navigated to the product, falling back to the first assigned collection.
Updated schema using current_collection:{
"@type": "ListItem",
"position": 2,
"name": "{{ current_collection.title }}",
"item": "{{ shop.url }}{{ current_collection.url }}"
}Step 4: Add Nested Collection Support
For stores with parent/child collection hierarchies (using collection metafields or tags), extend the breadcrumb logic:{% if current_collection.metafields.custom.parent_collection %}
{% assign parent_collection_handle = current_collection.metafields.custom.parent_collection %}
{% assign parent_collection = collections[parent_collection_handle] %}
{
"@type": "ListItem",
"position": 2,
"name": "{{ parent_collection.title }}",
"item": "{{ shop.url }}{{ parent_collection.url }}"
},
{
"@type": "ListItem",
"position": 3,
"name": "{{ current_collection.title }}",
"item": "{{ shop.url }}{{ current_collection.url }}"
},
{% endif %}This assumes you store parent collection handles in a custom metafield. Adjust the metafield namespace and key to match your setup.How to Add Dynamic Breadcrumb Schema for Collection Pages
Collection page breadcrumbs show Home > Collection (or Home > Parent Collection > Collection for nested structures).Step 1: Open Collection Template
Access collection template file:- In theme code editor, open Templates/collection.liquid
- For OS 2.0 themes, edit sections/main-collection.liquid
Step 2: Insert Collection Breadcrumb Schema
Add this code to the collection template:<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{ shop.url }}"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ collection.title }}",
"item": "{{ shop.url }}{{ collection.url }}"
}
]
}
</script>The collection object provides title and URL automatically. This creates a two-level breadcrumb for standard collections.Step 3: Implement Parent Collection Logic
For nested collections, add parent collection detection:<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{ shop.url }}"
},
{% if collection.metafields.custom.parent_collection %}
{% assign parent_handle = collection.metafields.custom.parent_collection %}
{% assign parent = collections[parent_handle] %}
{
"@type": "ListItem",
"position": 2,
"name": "{{ parent.title }}",
"item": "{{ shop.url }}{{ parent.url }}"
},
{
"@type": "ListItem",
"position": 3,
"name": "{{ collection.title }}",
"item": "{{ shop.url }}{{ collection.url }}"
}
{% else %}
{
"@type": "ListItem",
"position": 2,
"name": "{{ collection.title }}",
"item": "{{ shop.url }}{{ collection.url }}"
}
{% endif %}
]
}
</script>This checks for a parent_collection metafield and builds three-level breadcrumbs when present, falling back to two levels for top-level collections.How to Add Dynamic Breadcrumb Schema for Blog Posts
Blog post breadcrumbs follow the pattern: Home > Blog > Article Title.Step 1: Access Article Template
Open the article template file:- Navigate to Templates/article.liquid
- For OS 2.0 themes, edit sections/main-article.liquid
Step 2: Insert Article Breadcrumb Schema
Add this code to the article template:<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{ shop.url }}"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ blog.title }}",
"item": "{{ shop.url }}{{ blog.url }}"
},
{
"@type": "ListItem",
"position": 3,
"name": "{{ article.title }}",
"item": "{{ shop.url }}{{ article.url }}"
}
]
}
</script>The blog and article objects provide titles and URLs automatically. This creates a three-level breadcrumb for all blog posts.Step 3: Handle Multiple Blogs
If your store uses multiple blogs (e.g., News, Guides, Updates), the schema adapts automatically because {{ blog.title }} pulls the current blog name:- Post in “News” blog: Home > News > Article Title
- Post in “Guides” blog: Home > Guides > Article Title
How to Add Dynamic Breadcrumb Schema for Standard Pages
Standard pages (About Us, Contact, FAQ) use simple two-level breadcrumbs: Home > Page Title.Step 1: Open Page Template
Access the page template:- Open Templates/page.liquid
- For OS 2.0 themes, edit sections/main-page.liquid
Step 2: Insert Page Breadcrumb Schema
Add this code to the page template:<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{ shop.url }}"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ page.title }}",
"item": "{{ shop.url }}{{ page.url }}"
}
]
}
</script>The page object provides title and URL. This works for all standard pages automatically.How to Create Universal Dynamic Breadcrumb Schema
Universal implementation adds breadcrumb schema to all page types from a single code block in theme.liquid.
Step 1: Open Theme Layout File
Access the main theme file:- In theme code editor, open Layout/theme.liquid
- Locate the closing </head> or </body> tag
Step 2: Insert Universal Breadcrumb Schema
Add this comprehensive code block:<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{ shop.url }}"
}
{% if template contains 'product' %}
{% if product.collections.size > 0 %}
,{
"@type": "ListItem",
"position": 2,
"name": "{{ product.collections.first.title }}",
"item": "{{ shop.url }}{{ product.collections.first.url }}"
}
{% endif %}
,{
"@type": "ListItem",
"position": {% if product.collections.size > 0 %}3{% else %}2{% endif %},
"name": "{{ product.title }}",
"item": "{{ shop.url }}{{ product.url }}"
}
{% elsif template contains 'collection' %}
,{
"@type": "ListItem",
"position": 2,
"name": "{{ collection.title }}",
"item": "{{ shop.url }}{{ collection.url }}"
}
{% elsif template contains 'article' %}
,{
"@type": "ListItem",
"position": 2,
"name": "{{ blog.title }}",
"item": "{{ shop.url }}{{ blog.url }}"
}
,{
"@type": "ListItem",
"position": 3,
"name": "{{ article.title }}",
"item": "{{ shop.url }}{{ article.url }}"
}
{% elsif template contains 'page' %}
,{
"@type": "ListItem",
"position": 2,
"name": "{{ page.title }}",
"item": "{{ shop.url }}{{ page.url }}"
}
{% endif %}
]
}
</script>This single block handles products, collections, blog posts, and pages. The template conditional determines which breadcrumb structure to generate.Step 3: Exclude Homepage from Schema
Wrap the entire schema block in a conditional to prevent breadcrumbs on the homepage:{% unless template == 'index' %}
<script type="application/ld+json">
...breadcrumb schema code...
</script>
{% endunless %}Homepages don’t need breadcrumbs since they’re the starting point of navigation.How to Handle Search Result Pages in Breadcrumb Schema
Search results pages require special handling because they don’t fit standard navigation hierarchies.Step 1: Detect Search Template
Add search detection to universal schema:{% elsif template contains 'search' %}
,{
"@type": "ListItem",
"position": 2,
"name": "Search Results",
"item": "{{ shop.url }}{{ request.path }}"
}
{% endif %}Step 2: Include Search Query in Breadcrumb
Display the actual search term in breadcrumbs:{% elsif template contains 'search' %}
,{
"@type": "ListItem",
"position": 2,
"name": "Search Results{% if search.terms %}: {{ search.terms }}{% endif %}",
"item": "{{ shop.url }}{{ request.path }}"
}
{% endif %}This creates breadcrumbs like “Home > Search Results: running shoes” for search pages.How to Validate Dynamic Breadcrumb Schema
Testing ensures dynamic breadcrumbs generate correctly across different page types.
Step 1: Test Multiple Page Types
Visit and validate these pages:- Product page – Verify collection appears in breadcrumb
- Collection page – Check collection title displays
- Blog post – Confirm blog name and article title show
- Standard page – Test page title appears
Step 2: Use Google Rich Results Test
Validate each page type:- Go to search.google.com/test/rich-results
- Enter page URL
- Click Test URL
- Verify “Breadcrumb” detected in results
Step 3: Verify Liquid Variable Output
Common issues with dynamic schema: Empty collection titles – Products not assigned to collections produce blank breadcrumb items. Use {% if product.collections.size > 0 %} conditionals to prevent this. Missing shop.url – URLs show as /collections/shoes instead of https://store.com/collections/shoes. Always prefix with {{ shop.url }}. Special characters in titles – Product or collection names with quotes break JSON syntax. Use | escape filter: “name”: “{{ product.title | escape }}”.How to Add Breadcrumb Schema Using Shopify Apps
Schema apps provide dynamic breadcrumb implementation without code editing.Step 1: Install a Schema App
Three apps support dynamic breadcrumbs: JSON-LD for SEO:- Free plan available
- Automatic breadcrumb generation for all page types
- Handles nested collections via metafields
- $5.99/month
- Visual breadcrumb configurator
- Custom breadcrumb rules per template
- $4.99/month
- Breadcrumb schema included with full SEO suite
- Multi-language breadcrumb support
Step 2: Configure Breadcrumb Settings
In app settings:- Enable Breadcrumb Schema toggle
- Select page types to include (products, collections, blogs, pages)
- Configure collection priority for products in multiple collections
- Set homepage label (Home, Homepage, Main Page)
Step 3: Test App-Generated Breadcrumbs
Verify app output:- Visit different page types
- View page source
- Locate BreadcrumbList schema
- Check accuracy of names and URLs
How to Fix Common Dynamic Breadcrumb Schema Errors
Position Numbers Skip or Duplicate
Error: Position goes 1, 2, 4 or shows 2, 2, 3 Cause: Conditional logic breaks position numbering Fix: Use dynamic position calculation:{% assign position = 1 %}
{
"@type": "ListItem",
"position": {{ position }},
"name": "Home",
"item": "{{ shop.url }}"
}
{% assign position = position | plus: 1 %}
{% if product.collections.size > 0 %}
,{
"@type": "ListItem",
"position": {{ position }},
"name": "{{ product.collections.first.title }}",
"item": "{{ shop.url }}{{ product.collections.first.url }}"
}
{% assign position = position | plus: 1 %}
{% endif %}Increment position variable only when adding breadcrumb items.Trailing Commas in JSON
Error: “Unexpected token” or JSON parse error Cause: Extra comma after last breadcrumb item Fix: Remove trailing commas from conditional blocks:{% if product.collections.size > 0 %}
,{
"@type": "ListItem",
"position": 2,
"name": "{{ product.collections.first.title }}",
"item": "{{ shop.url }}{{ product.collections.first.url }}"
}
{% endif %}Notice the comma before the opening brace, not after the closing brace.Missing URLs in Breadcrumb Items
Error: “Missing field ‘item’ (required)” Cause: Collection or product URL is blank Fix: Always include {{ shop.url }} prefix:"item": "{{ shop.url }}{{ collection.url }}"Never use collection.url alone, as it returns a relative path (/collections/shoes) not a full URL.Common Questions About Dynamic Breadcrumb Schema in Shopify
How Do Dynamic Breadcrumbs Handle Products in Multiple Collections?
Products assigned to multiple collections need logic to select which collection appears in breadcrumbs. Shopify doesn’t automatically determine the “primary” collection, so you must implement priority rules.The most effective approach uses the collection context. When customers navigate from a collection page to a product, that collection should appear in breadcrumbs:
{% assign breadcrumb_collection = collection %}
{% if breadcrumb_collection == blank %}
{% assign breadcrumb_collection = product.collections.first %}
{% endif %}This checks if a collection context exists (customer came from a collection page). If blank, it falls back to the first assigned collection.
For more control, prioritize featured collections using product metafields:{% if product.metafields.custom.primary_collection %}
{% assign primary_handle = product.metafields.custom.primary_collection %}
{% assign breadcrumb_collection = collections[primary_handle] %}
{% elsif collection %}
{% assign breadcrumb_collection = collection %}
{% else %}
{% assign breadcrumb_collection = product.collections.first %}
{% endif %}This hierarchy prioritizes: 1) manually assigned primary collection from metafield, 2) collection from navigation context, 3) first alphabetically assigned collection.
For products with parent/child collection relationships, add logic to detect collection hierarchy and build multi-level breadcrumbs accordingly.Can Breadcrumb Schema Display Collection Filters or Sort Parameters?
Breadcrumb schema should not include filter or sort parameters in URLs. Google expects breadcrumbs to represent the site’s content hierarchy, not user session state or URL parameters. Incorrect implementation including filters:"item": "{{ shop.url }}{{ collection.url }}?sort_by=price-ascending"This creates different breadcrumb URLs for the same collection depending on how users sorted products, which confuses search engines about your site structure.
Correct implementation uses canonical collection URLs:"item": "{{ shop.url }}{{ collection.url }}"Even if customers arrived at a product through filtered collection views (e.g., /collections/shoes?color=blue), breadcrumbs should reference the base collection URL (/collections/shoes).
For breadcrumb visual display (the actual HTML breadcrumbs shown to users), you can include filter context. But the structured data schema should always point to canonical URLs without parameters.Where Should Dynamic Breadcrumb Schema Code Go – Theme.liquid or Individual Templates?
Theme.liquid placement centralizes breadcrumb schema in one location, making maintenance easier but requiring more complex conditionals to handle different page types. Individual template placement separates schema by page type, simplifying logic but requiring updates across multiple files. Choose theme.liquid when:- You want single-point maintenance for all breadcrumbs
- Your store uses consistent navigation patterns across page types
- You’re comfortable with Liquid conditionals ({% if template contains ‘product’ %})
- Different page types need unique breadcrumb logic
- You prefer simpler, template-specific code
- You’re implementing breadcrumbs gradually across page types
Do Dynamic Breadcrumbs Work with Shopify Markets and Multiple Languages?
Dynamic breadcrumb schema works with Shopify Markets but requires language-aware implementation to display translated collection and product names in breadcrumbs. Shopify’s built-in translation system provides localized values for product.title and collection.title automatically when using Markets. Your existing dynamic breadcrumb code adapts to the current language without modifications:{
"@type": "ListItem",
"position": 2,
"name": "{{ collection.title }}",
"item": "{{ shop.url }}{{ collection.url }}"
}This outputs “Zapatos” for Spanish customers viewing a shoes collection, and “Shoes” for English customers, because {{ collection.title }} returns the translated value based on the customer’s language context.
URLs must include the language prefix for non-default languages. Shopify’s {{ collection.url }} handles this automatically:- English (default): /collections/shoes
- Spanish: /es/collections/zapatos
- French: /fr/collections/chaussures
"name": "{{ collection.title | t }}"Check your translation app’s documentation for schema compatibility. Most modern apps handle JSON-LD structured data automatically.How Often Should You Update Dynamic Breadcrumb Schema Code?
Dynamic breadcrumb schema requires updates only when Shopify changes Liquid template variables or you restructure your site navigation hierarchy. The code itself updates breadcrumb content automatically as you add products and collections.Review breadcrumb implementation quarterly to ensure: Liquid variables remain valid – Shopify occasionally deprecates template objects or changes syntax (like the OS 2.0 transition). Check Shopify’s developer changelog for breaking changes. Navigation structure matches breadcrumb logic – If you add collection hierarchies or new page types (lookbook pages, landing pages), update breadcrumb conditionals to include these templates. Schema.org specifications stay current – BreadcrumbList schema is stable, but Google occasionally updates required or recommended properties. Monitor Search Console for warnings. Immediate updates needed when:
- Migrating to OS 2.0 theme structure – Template and section architecture changes require relocating breadcrumb code
- Implementing nested collections – Add parent collection logic to support multi-level breadcrumbs
- Adding new template types – Create breadcrumb patterns for custom page templates
Need expert help with Shopify SEO? HiAgency’s technical SEO specialists implement schema markup, optimize site architecture, and deliver data-driven strategies that improve organic visibility. Get in touch to discuss your Shopify store’s SEO performance.
Author Profile

- HiAgency is a digital marketing and web development agency specializing in SEO optimization and content management solutions. We help businesses improve their online visibility through technical implementations, user experience enhancements, and strategic content organization.
Latest entries
Technical SEOAugust 20, 2026How to Submit a Website and Sitemap to Google
AI SEOAugust 15, 2026Claude Keyword Research: A Data-Backed Workflow for SEO
AI SEOAugust 14, 2026Claude for Marketing: Use Cases, Workflows and Prompts
AI SEOAugust 14, 2026Claude AI Review 2026: Features, Pricing, Pros and Cons



