Skip to main content

Schema markup (JSON-LD)

How to use it

  1. Publish the two global schemas — Organization and Website. Both are generated from your shop profile and need no input.
  2. Generate product markup, individually or across the catalogue.
  3. Run a Rich Results check to see what Google makes of it.
  4. 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

TypeScopeSource
OrganizationGlobalYour shop profile — name, description, contact email, brand logo
WebsiteGlobalYour shop
ProductPer productTitle, description, price, availability, brand, identifiers
FAQPer pageYour FAQ content
BreadcrumbPer pageCollection 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

A schema you disable is removed from your storefront

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.

A failed sweep is not a clean sweep

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.

Rate limiting is treated as a failure, not as an ending

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

CapabilityFreeStarterProAgencyEnterprise
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