What Shopify actually outputs for structured data and what it leaves out
I checked the schema output on a new client's Shopify store last month. Dawn theme, freshly updated, no customisation. The product pages had Product schema including name, price, availability, a description. No GTINs. No brand entity. No manufacturer field. Organisation schema existed on the homepage with a name and a URL and nothing else. Person schema didn't exist anywhere on the site.
This is roughly what I find on most Shopify stores I look at. Not broken schema because Shopify generates valid, syntactically correct markup. But thin schema that leaves out the specific fields that connect your products to the Shopping Graph and give AI shopping agents the verification data they need. The gap between what Shopify provides by default and what a well-structured product entity actually requires is significant, and most brands don't know it exists because nobody has told them to look.
This piece covers exactly what Shopify does and doesn't generate, where the specific gaps are, and what you need to do to close them.
What Shopify generates by default
Shopify's themes including Dawn, generate Product schema on PDPs through Liquid templates. The standard output includes the product name, description, a primary image, and an Offer block covering price, currency, availability, and the product URL. That's a functional starting point. It's also roughly where it stops.
What's missing from default Shopify Product schema in almost every theme I've examined: the GTIN field, the brand entity, the manufacturer field, and AggregateRating. These aren't obscure edge cases. They're the fields that connect your product to the canonical entity in Google's Shopping Graph, establish your brand as the authoritative source, and surface your review data in rich results.
Shopify does generate some Organisation schema on the homepage in some themes, but it's typically a name and a URL with nothing else. There is no sameAs properties, no legal identifiers, nothing that creates the cross-platform triangulation that matters for entity trust. Person schema is absent entirely. Shopify has no mechanism to generate it and no native field where the data would even live.
The GTIN problem on Shopify
Every Shopify product variant has a Barcode field in the Admin. The field is labelled "Barcode (ISBN, UPC, GTIN)." This is where most brands already store their EAN or GTIN when they set up products. The data exists in Shopify. It's just not making it into the schema.
Shopify's default Liquid templates don't pull the barcode field into the Product schema output. The field is used for the Google Shopping feed and for point-of-sale scanning, and the schema generation ignores it. So you can have a product with a perfectly valid, GS1-registered GTIN sitting in the Barcode field that your customers never see, your Merchant Center feed uses correctly, and your on-site schema doesn't know about.
The fix requires editing the Product schema section of your theme's Liquid files. In Dawn and most modern themes, the schema is generated in either sections/main-product.liquid or a dedicated snippets/structured-data.liquid file depending on your theme. Find the Offer block and add the following before the closing brace:
{% if product.selected_or_first_available_variant.barcode != blank %}
"gtin13": "{{ product.selected_or_first_available_variant.barcode }}",
{% endif %}
While you're in that block, add the brand entity if it isn't there:
"brand": {
"@type": "Brand",
"name": "{{ shop.name }}"
},
"manufacturer": {
"@type": "Organization",
"name": "{{ shop.name }}",
"url": "{{ shop.url }}"
},
For a DTC brand where every product is your own, hardcoding the brand name from shop.name is fine. If you carry third-party brands, you'll want a product metafield for brand name instead. Something like product.metafields.custom.brand so each product can reference the correct brand entity.
The variant-level complication
The code above outputs the GTIN for the currently selected variant. This is better than nothing, but it's not the complete picture.
Schema.org allows a Product entity to have multiple Offer blocks. It allows one per variant each with its own GTIN, price, and availability. This is the technically correct way to represent a product with multiple SKUs. Getting there in Shopify requires iterating through all variants in the Liquid template and generating an Offer block for each, which is more involved than the single-variant approach.
"offers": [
{% for variant in product.variants %}
{
"@type": "Offer",
"url": "{{ shop.url }}{{ product.url }}?variant={{ variant.id }}",
"priceCurrency": "{{ cart.currency.iso_code }}",
"price": "{{ variant.price | divided_by: 100.0 }}",
"availability": "{% if variant.available %}https://schema.org/InStock{% else %}https://schema.org/OutOfStock{% endif %}",
"itemCondition": "https://schema.org/NewCondition"
{% if variant.barcode != blank %}
,"gtin13": "{{ variant.barcode }}"
{% endif %}
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
For most brands this level of detail is worth the implementation effort because variant-level GTIN data is what allows the Shopping Graph to build a complete canonical entity for your product. One that aggregates data correctly regardless of which colour or size a customer is searching for.
Organisation schema is critical
Shopify's default homepage Organisation schema, where it exists at all, needs replacing rather than supplementing. The version that ships with most themes is too thin to do meaningful work.
Add the following as a JSON-LD snippet in your theme.liquid file so it appears on every page across the domain. This is the global entity declaration that connects your domain to your verified external profiles:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "{{ shop.name }}",
"legalName": "Your Legal Company Name Ltd",
"url": "{{ shop.url }}",
"logo": {
"@type": "ImageObject",
"url": "{{ settings.logo | img_url: 'master' }}"
},
"sameAs": [
"https://www.instagram.com/yourhandle",
"https://www.linkedin.com/company/yourcompany",
"https://twitter.com/yourhandle"
],
"vatID": "GB123456789"
}
</script>
The legalName, sameAs URLs, and vatID need to be hardcoded here. There's no Shopify setting they map to natively check each sameAs URL resolves to a current, active profile before adding it. A 404 in a sameAs array is worse than no sameAs at all.
Also, ensure your company name is consistent everywhere you use it online ACME Hammers Ltd, ACME Hammers Limited, or ACME Hammers. We don’t want to cause any potential red flags for Ai agents. They need to be sure that they can be confident that you are the official ACME Hammers Ltd.
The Merchant Center consistency gap
Shopify's Google channel generates a product feed for Merchant Center that does use the Barcode field for GTINs. If you've had your products set up in Shopify with barcodes from the start, your Merchant Center feed probably has GTIN data in it. Your on-site schema, before the fix above, almost certainly doesn't.
This inconsistency matters. Google uses both the feed and the on-site schema to build the canonical entity for your products in the Shopping Graph. When the two sources disagree like when the feed has a GTIN and the schema doesn't it creates ambiguity in the entity. Not a catastrophic failure, but a reduction in confidence that affects how authoritatively Google treats your product data.
After making the schema changes above, check your Merchant Center account for any GTIN errors in the diagnostics tab. The feed and schema should now be consistent. If Merchant Center is flagging GTIN warnings on products that do have barcodes in Shopify, check whether the barcodes are correctly formatted EAN-13 or UPC-A strings and verify them against GS1's Verified by GS1 tool before assuming the feed data is correct.
Review your schema
Shopify has no native review system. Whether your reviews are contributing structured data to the Shopping Graph depends entirely on your review app and, in some cases, which plan you're on.
Judge.me and Okendo both output solid AggregateRating schema on PDPs. The star rating and review count appear in the structured data alongside your Product markup, which allows them to contribute to your canonical entity in the Shopping Graph.
Yotpo's schema output depends on the plan; their entry-level plans have historically been inconsistent about generating structured data.
The way to check is straightforward: run a PDP through validator.schema.org and look for an AggregateRating property nested inside your Product schema. If your review app is working correctly you'll see it. If reviews are rendering visually on the page but not appearing in the schema output, your app either doesn't generate Review schema or has a configuration issue worth raising with their support.
Trustpilot is a different kind of signal and most brands misunderstand what it does
Trustpilot is widely used and genuinely valuable but not in the way most Shopify brands assume. When you embed a Trustpilot TrustBox widget on your site, the ratings are loaded via a JavaScript iframe. Crawlers read your page HTML, not the iframe contents. The rating data that displays visually on your page is not contributing to any structured data on your domain. You can have a Trustpilot widget on your homepage showing 4.8 stars from three thousand reviews and your Organisation schema has no idea it exists.
What Trustpilot does contribute is a third-party brand-level signal via its own domain. Google treats Trustpilot as a trusted reviews source and ingests Trustpilot data for seller ratings in Google Shopping — the aggregate star rating that appears next to your brand in Shopping results comes partly from this. This is a meaningful trust signal, but it operates at the brand and seller level, not at the individual product level.
The practical implication is that Trustpilot and a Shopify review app are doing different jobs. Trustpilot builds your seller rating and brand-level trust in Google's systems. A review app like Judge.me or Okendo contributes product-level AggregateRating schema to your PDPs, which feeds into the canonical product entity in the Shopping Graph. You need both, and one doesn't substitute for the other.
One thing most brands haven't done: add your Trustpilot profile URL to your Organisation schema's sameAs array. Your Trustpilot page is a verified, authoritative third-party page about your brand. Including it in sameAs helps connect your on-site entity to that external trust signal in a way that search engines and AI shopping agents can follow.
"sameAs": [
"https://www.instagram.com/yourhandle",
"https://www.linkedin.com/company/yourcompany",
"https://uk.trustpilot.com/review/yourdomain.com"
]
For drop-model brands where most SKUs are one-time only, the priority remains brand-level review signals over product-level.
But product-level AggregateRating schema on PDPs still contributes to the canonical entity during the drop window. Having both in place before launch is worth the setup time.
Theme modification versus schema apps
The alternative to editing Liquid files directly is using a schema app such as TinySEO, Schema Plus for SEO, and a handful of others handle structured data generation without requiring theme access. For teams without a developer resource or without comfort modifying theme files, these are a reasonable option.
The trade-off is how the schema gets injected. App-generated schema typically loads via JavaScript after the page renders rather than being part of the initial HTML response. For most crawlers this is fine. Especially the more important ones like Googlebot which renders JavaScript. But inline JSON-LD in the HTML is marginally more reliable and faster to process, which matters for a drop launch when you want new pages indexed quickly.
If you're modifying the theme yourself, do it on a duplicate theme first and test on a staging URL before pushing to production.
Run the output through validator.schema.org on a sample of PDPs and on the homepage before going live. Close to a drop is not the moment to discover a Liquid syntax error has broken schema across your entire catalogue.
The work I've described here isn't complicated but it does require someone with theme access and enough Liquid familiarity to make targeted edits without breaking anything. For most Shopify brands that means a developer, or a conversation with your agency. The changes themselves are small. Getting them on someone's task list and through a QA process before the next drop is the part that takes longer than it should.