This guide provides a clear, step-by-step process for setting up a fully dynamic JSON-LD product schema in Shopify using Liquid. It is designed for those already familiar with using Liquid templates and metafields. If you are an SEO, this is the perfect resource to share with your developers.
I will walk you through optimising product pages for rich results and free Google Shopping ads, ensuring your product data is always accurate and up to date. This helps maximise visibility across key features like Popular Products, Shopping Knowledge Panels, and Google Images.
By refining your structured data, you will improve how products appear in search results, boost user engagement, and support inclusion in free Google Shopping ads. This can enhance both your organic visibility and paid search performance.
If you are new to Liquid, I'd strongly suggest checking out Shopify’s Liquid reference docs to build on your knowledge before diving in.
Here’s what it can do for your products:
For this guide, the naming conventions need to match exactly, as shown below. If they don’t, the Liquid code won’t pull the data correctly. Getting this right now saves time fixing errors later.
Image Below: Setting up custom metafields
Metafield Configuration Example:
After implementing and testing this schema, you may want to edit out or tweak the default elements; such as the shippingDestination and priceValidUntil.
For SEOs, this isn’t just about ticking a box in your technical SEO checklists. It’s about giving products the best chance to show up in product searches with rich results, qualifying for free Google Shopping listings, and improving overall visibility. The key benefit here is automation; once it’s in place, the schema handles itself.
I’ve also covered optimisations for Merchant Center schemas, like shipping details and return policies. These aren’t just nice extras; they help Google present more complete product information, which can improve click-through rates and make your listings more competitive.
The outcome? Better search performance, more visibility in Shopping ads, and structured data that doesn’t break every time a product gets updated. Clean, scalable, and effective; exactly what you need for clients running Shopify stores.
Thanks for reading, and I hope you got value from reading this Shopify guide on the Product & Merchant Center Schema for Shopify.
I will walk you through optimising product pages for rich results and free Google Shopping ads, ensuring your product data is always accurate and up to date. This helps maximise visibility across key features like Popular Products, Shopping Knowledge Panels, and Google Images.
By refining your structured data, you will improve how products appear in search results, boost user engagement, and support inclusion in free Google Shopping ads. This can enhance both your organic visibility and paid search performance.
If you are new to Liquid, I'd strongly suggest checking out Shopify’s Liquid reference docs to build on your knowledge before diving in.
Why Use Fully Dynamic JSON-LD Schema?
In eCommerce, structured data isn’t just a technical nice-to-have. It’s how you make sure search engines actually understand your product data. When search engines can process that information properly, it leads to better visibility, richer search results, and more clicks.Here’s what it can do for your products:
- Improved Visibility: Your products stand a better chance of showing up with rich snippets that highlight key details like price, availability, and reviews.
- Higher Click-Through Rates (CTR): The more accurate and detailed your listings look, the more likely people are to click. Simple as that.
- Better User Experience: Shoppers get the information they need upfront, which makes their decision-making process quicker and easier.
Step 1: Set Up Your Metafields
Before adding any code, you need to configure metafields in Shopify to store the required product data. These metafields are essential for structured data, ensuring accurate product schema for Google Search, rich results, and Merchant Center features like free Shopping ads, shipping details, and return policies.For this guide, the naming conventions need to match exactly, as shown below. If they don’t, the Liquid code won’t pull the data correctly. Getting this right now saves time fixing errors later.
Image Below: Setting up custom metafields
Metafield Configuration Example:
- Namespace: custom
- Keys:
- mpn (Manufacturer Part Number)
- gtin13 (if available and valid)
- size (for products where size is relevant)
Merchant Center Data:
- Namespace: custom
- Keys:
- shipping_rate – Shipping cost value
- shipping_currency – Currency code (e.g., GBP, USD)
- shipping_country – Destination country (two-letter country code)
- handling_time_min – Minimum handling time in days
- handling_time_max – Maximum handling time in days
- transit_time_min – Minimum delivery transit time in days
- transit_time_max – Maximum delivery transit time in days
- return_policy_country – Country where return policy applies
- return_days – Number of days the product can be returned
- return_method – Return process (e.g., ReturnByMail, ReturnInStore)
- return_fees – Whether return shipping is free or not
How to Add Metafields in Shopify:
- Go to your Shopify Admin Panel.
- Navigate to Settings > Custom Data.
- Choose Products (or Variants if you prefer variant-level data).
- Click Add definition to create new metafields:
- Specify the namespace as custom and the key (e.g., mpn, gtin13, size, shipping_rate).
- Define the content type based on the data, such as single-line text for MPN.
Step 2: Insert the JSON-LD Markup into Your Product Template
With your metafields configured, the next step is to add the dynamic JSON-LD markup to your product template.Where to Add the Code:
- In your Shopify Admin, go to Online Store > Themes.
- Click Actions Dropdown > Edit Code.
- Open your product template file (usually product.liquid or a section file like main-product.liquid).
Add the JSON-LD Code Snippet:
Paste the following Liquid code into your product template. This code dynamically pulls in product information, including titles, descriptions, prices, and metafields. It ensures your JSON-LD output is accurate, up-to-date, and aligned with Google’s current (2025) structured data guidelines.After implementing and testing this schema, you may want to edit out or tweak the default elements; such as the shippingDestination and priceValidUntil.
Code:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "{{ product.title | escape }}",
"image": [
{% if product.images.size > 0 %}
{% for image in product.images %}
"{{ image | img_url: 'large' }}"{% unless forloop.last %},{% endunless %}
{% endfor %}
{% endif %}
],
"description": "{{ product.description | strip_html | escape }}",
{% if product.selected_or_first_available_variant.sku != blank %}
"sku": "{{ product.selected_or_first_available_variant.sku | escape }}",
{% endif %}
"brand": {
"@type": "Brand",
"name": "{{ product.vendor | escape }}"
},
{% if product.selected_or_first_available_variant.metafields.custom.mpn != blank %}
"mpn": "{{ product.selected_or_first_available_variant.metafields.custom.mpn | escape }}",
{% endif %}
{% if product.selected_or_first_available_variant.metafields.custom.gtin13 != blank %}
"gtin13": "{{ product.selected_or_first_available_variant.metafields.custom.gtin13 | escape }}",
{% endif %}
"productID": "{{ product.id }}",
"offers": {
"@type": "Offer",
"priceCurrency": "{{ shop.currency }}",
"price": "{{ product.selected_or_first_available_variant.price | money_without_currency }}",
"priceValidUntil": "{{ 'now' | date: '%Y-%m-%d' | date: '%s' | plus: 31536000 | date: '%Y-%m-%d' }}",
"itemCondition": "https://schema.org/NewCondition",
"availability": "{% if product.available %}https://schema.org/InStock{% else %}https://schema.org/OutOfStock{% endif %}",
"url": "{{ shop.url }}{{ product.url }}",
"seller": {
"@type": "Organization",
"name": "{{ shop.name | escape }}"
},
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": {
"@type": "MonetaryAmount",
"value": "{{ product.metafields.custom.shipping_rate | default: '0' }}",
"currency": "{{ product.metafields.custom.shipping_currency | default: shop.currency }}"
},
"shippingDestination": {
"@type": "DefinedRegion",
"addressCountry": "{{ shop.address.country_code | default: 'US' }}"
},
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": {
"@type": "QuantitativeValue",
"minValue": "{{ product.metafields.custom.handling_time_min | default: '0' }}",
"maxValue": "{{ product.metafields.custom.handling_time_max | default: '1' }}",
"unitCode": "DAY"
},
"transitTime": {
"@type": "QuantitativeValue",
"minValue": "{{ product.metafields.custom.transit_time_min | default: '1' }}",
"maxValue": "{{ product.metafields.custom.transit_time_max | default: '5' }}",
"unitCode": "DAY"
}
}
},
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "{{ product.metafields.custom.return_policy_country | default: shop.address.country_code }}",
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": "{{ product.metafields.custom.return_days | default: '30' }}",
"returnMethod": "https://schema.org/{{ product.metafields.custom.return_method | default: 'ReturnByMail' }}",
"returnFees": "https://schema.org/{{ product.metafields.custom.return_fees | default: 'FreeReturn' }}"
}
}
{% if product.selected_or_first_available_variant.metafields.custom.size != blank %},
"additionalProperty": [
{
"@type": "PropertyValue",
"name": "Size",
"value": "{{ product.selected_or_first_available_variant.metafields.custom.size | escape }}"
}
]
{% endif %},
{% if product.metafields.reviews.rating_value != blank or product.metafields.reviews.review_count != blank %}
"aggregateRating": {
"@type": "AggregateRating",
{% if product.metafields.reviews.rating_value != blank %}
"ratingValue": "{{ product.metafields.reviews.rating_value }}",
{% endif %}
{% if product.metafields.reviews.review_count != blank %}
"reviewCount": "{{ product.metafields.reviews.review_count }}"
{% endif %}
}
{% endif %}
}
</script>
How Does This Code Work?
This code functions like a dynamic system that adapts based on the product data available in your Shopify store. Here’s how each part contributes to creating an accurate, structured JSON-LD output:Key Functions of the Liquid Code:
- Pulls Dynamic Data:
It uses Liquid objects like {{ product.title }}, {{ product.description }}, and others to automatically populate product details. It also loops through all product images to ensure a complete and accurate visual representation, with fallback handling if no images are available. - Handles Variants:
The code accesses the primary variant using product.selected_or_first_available_variant, ensuring that price, SKU, and variant-specific metafields like MPN, GTIN, and size are accurately reflected for each product variant. - Uses Metafields with Defaults:
It retrieves additional product details from your configured metafields (such as mpn, gtin13, and size). If any of these metafields are not set, the code provides default handling to maintain clean and valid structured data. - Builds Structured Offers & Shipping Data:
The offer section is dynamically constructed to include price details, stock availability, and shipping information, all based on your store’s current settings and product status. - Ensures Data Validity:
The code includes conditional logic to output fields like GTIN-13 only if the corresponding metafield contains valid data. This approach helps prevent errors and ensures compliance with structured data guidelines.
Step 3: Test & Validate Your JSON-LD
After implementing the code, it’s important to test and validate the structured data to ensure it’s working correctly.- Save Your Theme File:
Make sure to save any changes to your theme files in Shopify. - Refresh a Product Page:
Load one of your product pages to trigger the new JSON-LD output. - Run a Google Rich Results Test:
Go to Google’s Rich Results Test and enter the URL of your product page. This tool will analyse the structured data and highlight any issues. - Review for Errors or Warnings:
Check the test results for errors or warnings. Confirm that all dynamic values, such as price, SKU, and metafields, are populated correctly.
Wrapping it up
That’s it. With this setup, you’ve got fully dynamic JSON-LD running on your Shopify product pages. There are no manual updates, and there is no messing around every time a product changes. The schema pulls everything it needs directly from the store, keeping your structured data accurate and always in sync with live product data.For SEOs, this isn’t just about ticking a box in your technical SEO checklists. It’s about giving products the best chance to show up in product searches with rich results, qualifying for free Google Shopping listings, and improving overall visibility. The key benefit here is automation; once it’s in place, the schema handles itself.
I’ve also covered optimisations for Merchant Center schemas, like shipping details and return policies. These aren’t just nice extras; they help Google present more complete product information, which can improve click-through rates and make your listings more competitive.
The outcome? Better search performance, more visibility in Shopping ads, and structured data that doesn’t break every time a product gets updated. Clean, scalable, and effective; exactly what you need for clients running Shopify stores.
Thanks for reading, and I hope you got value from reading this Shopify guide on the Product & Merchant Center Schema for Shopify.
Last edited: