SkuWatch AI Visibility Agent Scan your store or site

Structured product data

How to Add Product JSON-LD to a Shopify Theme

Core answer

Add one authoritative Shopify Product or ProductGroup graph, preserve variant offers, and avoid the duplicate-schema failures seen on public storefronts.

By skuwatch editor

Difficulty
Advanced
Time
60 minutes
Risk
Theme changes
Last tested
July 27, 2026
SkuWatch AI Visibility loopFix

What you will verify

You will identify existing Product JSON-LD owners, add Shopify’s product structured-data output only when needed, and verify that title, variant, price, currency, availability, SKU, canonical URL, and reviews agree with the public page.

Do not begin by pasting a second Product block. Duplicate ownership is a more common Shopify failure than having no JSON-LD at all.

Public cases that define the risk

Observed July 27, 2026:

Store Machine-readable condition Why it matters
The Woobles two Product offers said InStock while page said sold out a valid graph can publish wrong commerce facts
Rhode two size Product entities had different prices but the same observed SKU variant identity can be ambiguous
HexClad UK Product name ended with Default Title internal Shopify labels can leak publicly
Gymshark no Product entity detected in initial JSON-LD response returned and browser-rendered output may differ

The goal is one coherent product graph, not the highest number of schema fields.

Before changing the theme

Save a baseline for four fixtures:

  • a simple one-variant product
  • a multi-variant product
  • an in-stock product
  • a sold-out product
url='https://example.com/products/example-product'
curl -sSL "$url" -o before.html
rg -n 'application/ld\+json|ProductGroup|"@type"[[:space:]]*:[[:space:]]*"Product"' before.html

In a browser, inventory scripts:

[...document.querySelectorAll('script[type="application/ld+json"]')]
  .map((node, index) => {
    try { return { index, value: JSON.parse(node.textContent) }; }
    catch (error) { return { index, error: error.message }; }
  });

Assign every block to the theme, review app, SEO app, or client-side integration.

Exact Shopify Admin path

Online StoreThemes → duplicate the live theme → Edit code

Search for:

application/ld+json
structured_data
schema.org
aggregateRating

If an authoritative Product graph already exists, repair it instead of adding another.

Add Shopify’s maintained output

Shopify documents the structured_data Liquid filter for product and article objects. It can output Product for a product without variants and ProductGroup when variants exist.

Add this once in the product template or product section only if no authoritative equivalent exists:

{% if request.page_type == 'product' and product != blank %}
  <script type="application/ld+json">
    {{ product | structured_data }}
  </script>
{% endif %}

Do not wrap the filter output in json; it already returns structured JSON text.

Preserve visible product evidence

The graph should agree with:

  • product.title
  • selected or first available variant
  • current market currency
  • selected variant price
  • selected variant availability
  • SKU or barcode where maintained
  • canonical product URL

Do not manually add a rating unless the same rating and review population are visible on the page.

Avoid Default Title

A simple Shopify product commonly has one internal variant called Default Title. If custom JSON-LD constructs a name from product plus variant title, conditionally omit it.

{% assign current_variant = product.selected_or_first_available_variant %}
{% capture public_name %}{{ product.title }}{% endcapture %}
{% unless current_variant.title == 'Default Title' %}
  {% capture public_name %}{{ product.title }} — {{ current_variant.title }}{% endcapture %}
{% endunless %}

Use this only in a deliberately maintained custom graph. Prefer Shopify’s maintained filter where it meets the store’s needs.

Expected result

  • one parent product identity
  • recoverable variants with stable identifiers
  • correct current offer for each selected variant
  • no internal labels
  • no unsupported aggregate rating
  • canonical URL and market context agree

Common failure modes

  • theme and SEO app each emit a complete Product
  • review app emits a second stale Offer
  • first variant price is used after another variant is selected
  • compare-at price is presented as current price
  • inventory policy is confused with actual availability
  • localized page exposes another market’s currency

Verify public output

curl -sSL -H 'Cache-Control: no-cache' "$url" -o after.html
diff -u before.html after.html

Test all four fixtures. Validate meaning before syntax: the most important check is agreement with the buy box.

Rollback

Publish from a duplicate theme. Retain the previous theme version and document any app embed disabled during consolidation.

Primary source: Shopify structured_data filter.

Community discussion

Add to the article

Ask a technical question, share a storefront result, or challenge a conclusion with evidence.

Comments are public. Do not post customer data, credentials, private store information, promotional spam, or unsupported accusations. Comments may be moderated.