Hey @sharmavin97 — great question, and you’re thinking about this the right way. Here’s a complete guide to handle this safely.
How Shopify structured data works
In most modern Shopify themes (Dawn and its descendants), the Product JSON-LD schema is output in a separate snippet, not embedded inside the visible product section. Look for a file like:
snippets/structured-data.liquid
-
snippets/product-structured-data.liquid
-
- or a
<script type=”application/ld+json”> block inside sections/main-product.liquid
- Open your theme code and search for
"@type”: “Product” or application/ld+json — that will show you exactly where it lives.
-
The safe approach: Separate schema from layout
The key principle is to decouple the structured data output from the visual layout. Here’s how:
Step 1 — Extract the schema into its own snippet
If the JSON-LD is currently inside your default product section, cut it out and place it in a dedicated snippet, e.g. snippets/product-schema.liquid
liquid
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Product",
"name": {{ product.title | json }},
"url": {{ canonical_url | json }},
"description": {{ product.description | strip_html | json }},
"image": [
{% for image in product.images %}
{{ image | image_url: width: 1200 | prepend: 'https:' | json }}{% unless forloop.last %},{% endunless %}
{% endfor %}
],
"brand": {
"@type": "Brand",
"name": {{ product.vendor | json }}
},
"sku": {{ product.selected_or_first_available_variant.sku | json }},
"offers": {
"@type": "Offer",
"url": {{ canonical_url | json }},
"priceCurrency": {{ cart.currency.iso_code | json }},
"price": {{ product.selected_or_first_available_variant.price | divided_by: 100.0 | json }},
"availability": {% if product.selected_or_first_available_variant.available %}"https://schema.org/InStock"{% else %}"https://schema.org/OutOfStock"{% endif %},
"seller": {
"@type": "Organization",
"name": {{ shop.name | json }}
}
}
}
</script>
```
**Step 2 — Include it in your theme layout**
In your `layout/theme.liquid`, include this snippet inside the `<head>` tag or just before `</body>` on product pages:
```liquid
{% if template == 'product' %}
{% render 'product-schema' %}
{% endif %}
```
This way, **no matter what sections you add, remove, or replace** on the product template, the structured data is always rendered independently.
---
**For reviews / ratings (if applicable)**
If you use a reviews app (like Yotpo, Judge.me, Loox, etc.), they typically inject their own `aggregateRating` block automatically. Check their documentation before adding it manually to avoid duplicates.
---
**For regular pages**
You're correct — as long as the content is rendered in the HTML (even inside custom sections) and your meta title/description are set, there's no SEO risk. Just make sure content isn't hidden via `display: none` or rendered only via JS after page load, as Googlebot may not always execute JavaScript reliably.
---
**Testing checklist**
After making your changes:
1. **Google Rich Results Test** — https://search.google.com/test/rich-results — paste your product URL and confirm Product schema is detected.
2. **View Page Source** (Ctrl+U) — search for `application/ld+json` to confirm the schema block is present in raw HTML.
3. **Google Search Console** → Enhancements → Shopping — monitor for any structured data errors after deploying.
---
**TL;DR**
- Find where `"@type": "Product"` lives in your theme code.
- Move it to a dedicated snippet (`snippets/product-schema.liquid`).
- Render it conditionally from `layout/theme.liquid`.
- Then freely customize your product section layout without any SEO risk.
Hope this helps! Feel free to share your theme name if you need more specific guidance.