A restrained markup model in which every node, @id, and relationship agrees with the page's visible, verifiable claims.

Each template gets one page role and one primary entity. We remove duplicate or unsupported nodes, then validate the rendered production output. The draft isn't the acceptance state. Every JSON-LD block on the site says the same thing the page and the approved graph already say, checked on the live pages. Technical SEO and engineering leads whose templates each generate their own version of the same entity in structured data.

Figure slotting a labeled node into a large node-and-edge lattice representing schema markup

Some of the 500+ brands we've worked with

See all references
  • GE
  • Silverline
  • AVVA
  • Lezzet
  • Ekol
  • Yolcu360
  • Amazon
  • BMW
  • Shell
  • Hyundai
  • PepsiCo
  • Red Bull
  • Decathlon
  • MediaMarkt
  • Bayer
  • Sanofi
  • EY
  • KPMG
  • 3M
  • Domino’s
  • Lexus
  • Trendyol
  • Hepsiburada
  • Yandex

Five steps from the approved graph to a validated, deployed template.

How we hold ourselves to it

  • One @id per template
  • Visible-content parity
  • Production gets checked
  • No invented relationships
  1. Map templates to entity roles

    Every page gets one documented role and one permitted slice of the approved public graph before any markup is written. Content, entity, and technical owners approve each template's role and the graph boundary it's allowed to touch.

    A template-to-entity map with the primary @id and the graph fragment each page is allowed to express.

  2. Reconcile identifiers with the canonical graph

    Current identifiers and canonical URLs get checked against the register before any relationship gets attached to them. The entity owner and an engineer approve merge, retain, or replace for every identifier that doesn't already match.

    An identifier reconciliation register with merge, retain, or replace decisions for every @id.

  3. Verify every relationship against evidence

    Each proposed relationship gets checked for direction, an approved graph edge, and visible-page support before it ships. Domain, privacy, and legal owners approve relationship direction and reject anything unsupported or prohibited.

    An approved relationship register that records every unsupported edge as an explicit rejection.

  4. Remove duplicate and unsupported markup

    Duplicate nodes and relationships the visible page can't support get traced and removed in a sequence that doesn't break dependent templates. Engineering, content, and entity owners approve the removal scope, migration order, and rollback plan.

    A defect map with a safe removal sequence and affected-template dependencies.

  5. Validate production syntax and parity

    We parse the live JSON-LD and compare identifiers, edges, and visible facts on representative and edge-case pages after release. An independent technical SEO reviewer approves only output that passes the original graph and visible-parity rules.

    A syntax, parity, and regression report from the actual deployed pages.

Engineering gets one implementable template specification, along with a metric showing whether live pages still match the approved model.

  • Entity markup audit

    A rendered-page audit of duplicate identities, conflicting @id values, and edges the visible page doesn't support.

  • Schema relationship specification

    Canonical nodes, directed edges, provenance, and explicit exclusions, mapped by template.

  • Reusable template implementation plan

    Ownership, examples, and safe reference behavior included, so an editor can't accidentally recreate the duplication problem.

  • Graph parity rate

    Measured on the live deployment, with the page set and the pass rule both agreed before we compare anything, so a passing draft that regresses in production doesn't get counted as a win.

  • Parity fixtures wired into your release pipeline

    A release reruns the check when a template, identifier, or relationship changes. A previous pass isn't evidence that the markup stayed stable.

Two templates emit two different @id values for the same organization, and the JSON-LD claims a relationship the visible copy never mentions.

A good fit when

  • Every template invents its own markup — The about page, the product page, and the author bio each generate their own Organization node.
  • The graph and the page disagree — A JSON-LD block asserts a "parentOrganization" relationship or a job title that the visible text on the same page never states.
  • Identifiers drift across locales or templates — The English page and its localized variant use two canonical URLs, splitting one node into two.
  • An approved entity graph already exists — This method implements an agreed canonical model, and a missing one goes to Entity Relationship Mapping first.
  • Each template resolves to one primary @id — It also carries a documented purpose and a primary entity taken from the approved graph.
  • Visible content must support every property — A fact belongs in JSON-LD only when a reader can verify it from the page's visible text.
  • The deployed output needs its own check — A build step, a caching layer, or a CMS default can quietly change what ships. We check the live production output.

Better handled as other work when

  • You want a guaranteed rich result — Correct markup makes a page eligible to be understood, and it forces no rich result, panel, or AI citation.
  • Invented relationships are prohibited — Syntactically valid markup still fails when its meaning is false. Leaving the field empty is safer than inventing a value.
  • You want the markup to guarantee an outcome — Markup earns eligibility, and a well-formed JSON-LD block still cannot manufacture a real relationship.
  • Schema App

    authors the JSON-LD itself, tied to the one approved graph so duplicate nodes can't slip in

  • InLinks

    proposes the template's entity references from page content, keeping the graph fragment minimal

  • Schema.org Validator

    the vendor-neutral syntax check, separate from any one engine's own rules

  • Google Rich Results Test

    the live-parity check on rendered production output, not the draft

  • Screaming Frog

    extracts rendered JSON-LD across templates so duplicate @id values surface as a list

  • Sitebulb

    validates markup during the crawl and groups failures by the template that produced them

A current template and its rendered markup are enough to start. Zeo traces each block to its approved entity, flags unsupported properties, and checks the production result.
Validate your JSON-LD

What remains outside the scope of valid schema?

Markup makes a page eligible to be understood accurately by machines. It can't create a real-world relationship or determine how an external system displays one.

Do I need this if my templates already emit JSON-LD?

You may still need it when templates assign different identifiers to the same entity or assert facts the visible page never states.

Can I rely on automation alone, or is there human review?

Inventorying rendered markup, reconciling identifiers, and drafting template specs can all be automated. The judgment calls stay with people, who approve which relationships are real, which templates can implement them, and what deploys.

How do you know the markup is still correct after launch?

We calculate graph parity rate from the live production pages. The check parses deployed JSON-LD and compares it with the approved graph and visible page facts. Draft output isn't part of the rate. If a reviewed template regresses after deployment, the next check records the failure.