An SEO’s Guide to Writing Structured Data (JSON-LD) [Schema @ID]

No Comments
An seo’s guide to writing structured data (json-ld) [schema @id]

AI Summary

Write structured data as JSON-LD in a single <script type="application/ld+json"> block, wrap the entities in an @graph, and give each one a stable @id so nodes reference each other instead of being redeclared on every page. Validate with both the Schema Markup Validator and Google's Rich Results Test before shipping, then watch the type-specific reports under Enhancements in Search Console.

  • An @id is a stable URI naming a node, conventionally your canonical URL plus a lowercase fragment such as #organization.
  • Site-wide entities keep the same @id on every page; page-level entities use that page's canonical URL as the base.
  • Only mark up content that is actually visible on the rendered page. That is the line between structured data and spam.
  • Structured data is not a ranking factor. It buys rich-result eligibility and entity clarity, nothing more.
  • Valid markup only makes you eligible: Google can still withhold the rich result on quality, mismatch, or type restrictions.
Diagram contrasting structured data without @id, where three pages each redeclare separate organization and website nodes, against the @graph and @id pattern where article, website and webpage nodes all reference a single organization node declared once.
Without @id, every page creates duplicate entities. With @graph and @id, the Organization is declared once and every other node points at it.

Quick answer: To write structured data as an SEO, use JSON-LD in a single <script type="application/ld+json"> block, give every entity a stable @id so nodes can reference each other instead of being duplicated, and only mark up content that is actually visible on the page. Validate with Google's Rich Results Test before shipping, then monitor the type-specific reports under Enhancements in Search Console for errors after deployment.

Why JSON-LD Beats Microdata and RDFa in Practice

Google accepts three structured data formats, but JSON-LD is the one Google explicitly recommends, and after two decades of doing this I have stopped using anything else. The practical reasons: JSON-LD lives in one script block instead of being woven through your HTML attributes, so a template redesign cannot silently break it; it can be injected via a tag manager or a server-side layer without touching the theme; and it is diffable in code review, which microdata scattered across forty template partials is not. The only time I still encounter microdata is legacy e-commerce platforms, and my standard recommendation is to migrate during the next replatform rather than maintain two formats in parallel.

The @id Pattern: Building a Connected Entity Graph

The single biggest quality jump in most sites' structured data comes from using @id correctly. Without it, every page redeclares your Organization, your logo, and your author from scratch, and parsers see dozens of disconnected duplicate entities. With it, you declare each entity once and reference it everywhere else.

An @id is just a URI that acts as a stable name for a node. It does not need to resolve to a real page, but the convention that works well is your canonical URL plus a fragment:

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Example Co",
      "url": "https://example.com/",
      "logo": {
        "@type": "ImageObject",
        "@id": "https://example.com/#logo",
        "url": "https://example.com/assets/logo.png"
      }
    },
    {
      "@type": "WebSite",
      "@id": "https://example.com/#website",
      "url": "https://example.com/",
      "publisher": { "@id": "https://example.com/#organization" }
    },
    {
      "@type": "Article",
      "@id": "https://example.com/blog/post/#article",
      "headline": "Post title here",
      "author": { "@id": "https://example.com/#organization" },
      "publisher": { "@id": "https://example.com/#organization" },
      "isPartOf": { "@id": "https://example.com/#website" }
    }
  ]
}

Notice the pattern: the Organization is defined once with its full properties, then author, publisher, and isPartOf point at it with a bare { "@id": "..." } reference. That is the whole trick. Site-wide entities (#organization, #website) keep the same @id on every page; page-level entities (#article, #breadcrumb, #webpage) use the page's own canonical URL as the base. Keep fragments lowercase and consistent forever: changing them later means parsers see brand-new entities.

The payoff compounds beyond one page. Because the same #organization node appears in the graph of every page on the site, each page reinforces one entity rather than introducing another candidate. That is the mechanical half of the entity work described in entity HTML and becoming a machine-readable brand: consistent identifiers are what let a parser merge your pages into a single subject instead of a pile of lookalikes.

Schema Types Worth Writing: Requirements and What You Get

Not every type earns a rich result, and Google has retired several over the years (HowTo and FAQ rich results are now heavily restricted). This table reflects what is actually worth implementing on most sites:

Schema typeMinimum required propertiesRich result eligibility
Article / BlogPostingheadline, image, datePublished, author (with name)Yes: article features in mobile results and Discover
Productname, plus offers (with price, priceCurrency, availability) or review or aggregateRatingYes: price, stock, star snippets; merchant listing features
BreadcrumbListitemListElement with position, name, itemYes: replaces raw URL in the snippet with the crumb trail
Organizationname, url; add logo, sameAsNo standalone rich result: feeds the knowledge panel and entity understanding
LocalBusinessname, address; add geo, openingHoursSpecification, telephoneYes: local knowledge panel details
FAQPagemainEntity of Question/Answer pairsRestricted since 2023: rich result shown mainly for government and health sites; still useful as machine-readable content
VideoObjectname, thumbnailUrl, uploadDateYes: video thumbnails, key moments
JobPostingtitle, description, datePosted, hiringOrganization, jobLocationYes: Google Jobs surface

"Required" here means required for the rich result per Google's documentation; schema.org itself mandates almost nothing. Fill recommended properties too where you honestly have the data, but never invent values (fake aggregateRating is the classic manual-action magnet).

A Writing Workflow That Survives Contact With Production

My actual process for authoring structured data on a client site:

  1. Inventory templates, not pages. Structured data is a template-level decision. List each template (home, category, product, article, about) and decide which types belong on each.
  2. Write one reference JSON-LD block per template in a code editor, with real values from a live example page, using the @graph + @id pattern above.
  3. Validate twice: the Schema Markup Validator (validator.schema.org) checks vocabulary correctness; Google's Rich Results Test checks rich-result eligibility. They catch different problems: use both.
  4. Only mark up visible content. If the price, rating, or FAQ text is not on the rendered page, it does not belong in the markup. This is the line between structured data and spam.
  5. Ship, then request indexing on two or three representative URLs via URL Inspection and confirm the "Detected structured data" section in the inspection result.
  6. Monitor in Search Console: each eligible type gets its own report under the Enhancements section in the left navigation (e.g. "Products", "Breadcrumbs", "Videos"). Errors there mean lost eligibility; warnings mean missing recommended fields. Check them after every template deployment, not just at launch.

Where Each Problem Surfaces, and What It Means

The three validation surfaces do not overlap cleanly, and knowing which tool reports which class of problem saves a lot of wasted debugging. Read this as a routing table: find the symptom, then go to the fix.

Where you see itWhat it reportsTypical messageWhat it actually means
Schema Markup Validator (validator.schema.org)Vocabulary correctness against schema.org itselfUnrecognised property, invalid type for propertyYou misspelled a property or used one that does not belong on that type. Google may ignore it silently, so fix it here first
Rich Results TestEligibility for a specific Google rich resultMissing field offers, invalid value in priceCurrencyThe markup parses, but Google's requirements for that feature are unmet. Nothing will render until the required field is present
URL Inspection, live testWhat Google sees in the rendered page right nowDetected structured data shows fewer items than expectedRendering or caching problem: your JSON-LD is injected client-side and did not survive, or a cached HTML variant lacks it
Search Console Enhancements reportsAggregate status across all indexed URLs, after the factInvalid items trending up after a release dateA template deployment broke the block. The date the curve turns is the deployment to roll back or patch
Enhancements: valid but no rich resultEligibility granted, display withheldItems valid, impressions flatNot a markup problem. Quality, content mismatch, or type restriction is the constraint, so work the validation errors first, then the content

One ordering rule saves repeat trips: fix vocabulary errors before eligibility errors, and eligibility errors before you start theorising about trust. A property Google cannot parse will never produce a feature, no matter how strong the page is.

Mistakes I Keep Finding in Audits

  • Duplicate conflicting blocks: the theme, an SEO plugin, and a tag manager each injecting their own Organization with different names. Pick one source of truth and suppress the rest.
  • Markup/content mismatch: the JSON-LD says a product is in stock while the page says sold out, usually because the markup is cached differently than the page.
  • Dates that never update: dateModified hardcoded at launch. Wire it to the CMS field.
  • Relative URLs in @id or url: always absolute, always matching the canonical protocol and host.
  • Marking up the whole site as LocalBusiness when only the contact page describes a location.

Structured Data Within Your Content Strategy

Content strategy determines what you create, why, and how it serves both users and business objectives. This resource examines approaches for developing content that performs well in search while delivering genuine value.

Understanding User Intent

Effective content addresses what users actually need when they search. Analyzing search intent, understanding user questions, and mapping content to the user journey ensures content serves real needs. Intent alignment has become as important as keyword targeting.

Quality and Comprehensiveness

Search engines increasingly reward comprehensive, authoritative content over thin pages targeting specific keywords. Building topical depth through thorough coverage of subjects establishes expertise. Quality signals including E-E-A-T factors influence how content is evaluated. Structured data is the machine-readable layer of that same effort: it does not substitute for quality, but it removes ambiguity about who published what, when, and about which entities.

Content Lifecycle Management

Content requires ongoing maintenance to remain competitive. Regular audits identify content needing updates, consolidation, or removal. Fresh, accurate content maintains rankings while outdated content decays. Building content refresh into ongoing processes sustains performance. Fold structured data into the same audit cycle: every content refresh should also re-validate the page's JSON-LD, because schema requirements change more often than most teams expect.

Frequently Asked Questions

Does JSON-LD structured data improve rankings?

Not directly: Google has stated repeatedly that structured data is not a ranking factor. What it changes is eligibility for rich results and clarity of entity understanding, which affect click-through rate and how reliably Google connects your content to your brand. Treat it as a presentation and disambiguation layer, not a ranking lever.

Where should the JSON-LD script go on the page?

Google accepts it in the <head> or <body>, and it also works when injected by JavaScript (including Google Tag Manager) as long as the rendered DOM contains it. Server-side output in the <head> is the safest option because it does not depend on rendering, and it is what I implement whenever the stack allows it.

What is @id in schema markup and do I really need it?

An @id is a stable URI identifier for an entity, letting other nodes reference it instead of redefining it. Small sites with one block per page can live without it, but the moment you output multiple types per page (Article + Organization + WebSite + BreadcrumbList) the @graph/@id pattern prevents duplicate entities and keeps the graph coherent. It costs almost nothing to add, so I default to using it.

Can I put multiple schema types on one page?

Yes, and most pages should. Combine them in a single script using @graph rather than multiple separate script tags: one block is easier to maintain and lets nodes reference each other via @id. Just make sure each type genuinely describes the page's visible content.

How do I check whether my structured data is working?

Before launch, run the URL through Google's Rich Results Test and the Schema Markup Validator. After launch, open Search Console and check the type-specific reports under Enhancements in the left navigation, plus the "Detected structured data" panel inside URL Inspection for individual pages. Impressions on rich results also show up in Performance → Search results when you filter Search Appearance.

Why is my valid markup not producing a rich result?

Valid markup makes you eligible; it does not guarantee display. Google withholds rich results when the page or site quality is in doubt, when the markup does not match visible content, when the type is restricted (FAQ and HowTo since 2023), or simply per-query. If the Enhancements report shows the item as valid and weeks have passed, the markup is fine: the constraint is trust or relevance, and the fix is on the content side.

This resource provides strategic guidance for content programs that drive sustainable organic growth.

Source: https://moz.com/blog/writing-structured-data-guide

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

    About SEO ProCheck

    Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

    Work With Me

    Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

    Subscribe to our newsletter!

    More from our blog