Schema markup (JSON-LD)
How to use it
- Publish the two global schemas — Organization and Website. Both are generated from your shop profile and need no input.
- Generate product markup, individually or across the catalogue.
- Run a Rich Results check to see what Google makes of it.
- Watch the drift card and re-publish what has gone stale.
⏱ ~10 min setup · 💳 Starter+ · 🎯 Rich results in search, driven by your real catalogue data
What gets published
| Type | Scope | Source |
|---|---|---|
| Organization | Global | Your shop profile — name, description, contact email, brand logo |
| Website | Global | Your shop |
| Product | Per product | Title, description, price, availability, brand, identifiers |
| FAQ | Per page | Your FAQ content |
| Breadcrumb | Per page | Collection and product hierarchy |
Markup is written to a metafield on the resource, which your theme renders into the page. Both global schemas need zero input — the "Missing" state on the globals card is a Publish button, not a prompt to fill in a form.
Organization markup is built from your real shop profile: name, description, contact email and brand logo, falling back gracefully when a field is not set. Anything you enter yourself takes priority.
Disabling and deleting
Toggling markup off or deleting it re-publishes what remains active — and when nothing active remains, it deletes the metafield.
The reason for deleting rather than rewriting it empty: an empty rewrite leaves stale JSON-LD in place for Google to read. On older builds, disable and delete only changed the row in the app, so markup a merchant had deleted carried on rendering for search engines while the table said "inactive".
Drift detection
A drift sweep runs daily. It compares published markup against your live catalogue and flags entries whose source data has moved — a price change, a retitled product, an availability flip.
The card tells you when the sweep last ran, and flips to "as of … — re-check" once a report is more than seven days old. A snapshot with no age reads as current truth, which is exactly how a broken sweep stays invisible.
When a sweep fails — an expired Shopify token, a network failure — it persists a zero stale count, because zero is what the counter was initialised to. Reading that number without reading the status renders a green "all in sync" over a sweep that never completed.
The card now has a distinct failed state and shows the underlying error. Read the status before the count. The same rule applies to the Rich Results card and to the bulk generation job.
Rich Results checks
The Rich Results check submits published URLs to Google's testing API and reports what it found.
Errors and warnings are separate numbers. Google returns a verdict per URL
and annotations per detected item; a PASS verdict with warning annotations is
an eligible page with room to improve, not a failure. The headline figure is the
count of blocking problems.
Two details:
- Problems are deduplicated. Google reports issues per detected item, so a theme that emits its own Product entity alongside yours produces the same "missing field" several times over. Errors sort ahead of warnings.
- The checked window rotates. Each run inspects a different slice of your published URLs and remembers where it stopped, wrapping around. Without that, the same arbitrary first N URLs get checked forever and the rest are never inspected.
Bulk generation
Bulk generation walks your catalogue and generates markup for products that do not have it. It runs as a tracked background job.
Coverage is reported against your real catalogue size, so "50 of 2,229" is the honest number rather than a percentage of whatever the last page of results happened to contain.
Shopify signals GraphQL rate limiting inside a normal HTTP 200 response. A naive sweep reads the missing data as "end of catalogue", stops early, and records the job as done — reporting a partial pass as a complete one. Paged reads now retry with the real restore rate and raise an error when retries are exhausted, so a throttled run is recorded as failed. Write concurrency is capped so bulk publishing does not trigger the throttle in the first place.
Plan tiers
| Capability | Free | Starter | Pro | Agency | Enterprise |
|---|---|---|---|---|---|
| Organization + Website schemas | — | ✓ | ✓ | ✓ | ✓ |
| Per-product schema | — | ✓ | ✓ | ✓ | ✓ |
| FAQ + breadcrumb schema | — | ✓ | ✓ | ✓ | ✓ |
| Drift detection | — | ✓ | ✓ | ✓ | ✓ |
| Rich Results validation | — | ✓ | ✓ | ✓ | ✓ |
| Bulk catalogue generation | — | — | ✓ | ✓ | ✓ |
| Version history | — | — | ✓ | ✓ | ✓ |
Rich Results validation uses the Search Console connection.
Best practices
- Publish the globals first. Organization and Website markup is what ties every product entity to a recognised brand, and it takes one click.
- Check what your theme already emits. Many themes publish their own Product JSON-LD. Two entities on one page is not automatically a problem, but it is where most duplicate-field warnings come from.
- Treat warnings as a backlog, not an emergency. The blocking count is the one that costs you rich results.
- Re-check after a bulk price or availability change. That is precisely what the drift sweep is for.
- If the drift card says failed, fix the connection. Everything downstream of it is stale until you do.
See also
- Site audit — page-level SEO scoring, including structured data
- Technical health — schema publishes appear in the change timeline
- Sitemap — the other artefact you publish for search engines
- Storefront widgets overview — what else renders on your storefront