I have deployed JSON-LD schema on over 1,000 websites in eight years. For most of that time, schema was about earning rich results in Google. Star ratings, FAQ dropdowns, breadcrumbs in the SERP. That was the entire payoff.
That has changed. AI engines like ChatGPT, Claude, Gemini, and Perplexity now use structured data as one of the signals they lean on to decide which entity created a page, whether that entity is credible, and whether the content is worth citing. Schema has gone from a nice-to-have for rich snippets to a foundational signal for AI search visibility.
This guide walks through the exact @graph structure I use on every page I publish. Not theory. The actual JSON-LD, step by step, with the reasoning behind every node.
Use a single JSON-LD @graph block per page containing a Person or Organization node (with a sameAs array for entity disambiguation), a page-level type like BlogPosting or Service, a BreadcrumbList, and FAQPage or HowTo where visible content supports it. Connect every node using @id references. Every schema property must match something visible on the page. This is the structure I use across every site I work on, and it is the foundation that makes entity clarity possible for AI engines.
Why Schema Matters More in AI Search Than It Did in Traditional SEO
In traditional SEO, schema earned you rich results. If you added FAQPage markup, Google might show expandable questions in the SERP. If you added Review schema, you might get star ratings. The content itself still did most of the ranking work.
AI search works differently. When ChatGPT Search retrieves content to cite in an answer, it pulls from Bing's index. When Gemini formulates a response, it draws from Google's Knowledge Graph. Both of those systems use structured data to answer a fundamental question: who created this content, and can I trust them?
If the engine cannot disambiguate the entity behind a page, the page is harder to cite. It is not that schema guarantees a citation. It is that missing or broken schema removes a signal that AI engines use to build confidence in their sources. Across the client work I have done, I have consistently seen that entity-rich content with clear schema gets cited more often than equivalent content without it.
That last number is the one that matters most. If 68% of AI citations go to pages outside the traditional top 10, then the signals AI engines use to select sources are not the same as traditional ranking factors. Entity clarity, schema, and cross-platform corroboration fill that gap.
Why One @graph Block, Not Separate Script Tags
You can technically add schema as separate script tags. One for Person, one for BlogPosting, one for BreadcrumbList. It will validate. Google will read it. But you lose the most important part: the explicit connections between your entities.
A single @graph block lets you use @id references to link the Person node to the BlogPosting author field, the BlogPosting to the BreadcrumbList, and the FAQPage to the same page URL. This is what turns a collection of isolated facts into a connected entity picture. AI engines benefit from that connectedness because it mirrors how they reason about entities in the first place: as a web of relationships, not a list of standalone claims.
Think of it this way. Separate script tags are like handing someone three business cards from three different people. A single @graph is like handing them one business card where the name, the company, and the role all point to the same person. The second version is easier to trust.
The Full @graph Walkthrough, Step by Step
Here is every node I include, in the order I build them. Each step includes the code and the reasoning. If you want to see how all of this comes together in a real page, view the source on any blog post on this site.
This is the identity anchor for the entire graph. Everything else points back to it. For a personal brand, use Person. For a company, use Organization. For a freelancer who also runs an agency, I use Person for the individual site and Organization for the agency site.
The critical fields are @id (a stable URI that other nodes reference), name, url, image, and description. The description should be a concise, factual sentence that an AI engine could use as-is in a citation. Not marketing copy. A statement of who you are and what you do.
{
"@type": "Person",
"@id": "https://yoursite.com/#person",
"name": "Your Full Name",
"jobTitle": "Your Professional Title",
"url": "https://yoursite.com/",
"image": "https://yoursite.com/images/profile.png",
"description": "A factual one-line bio that describes what you do and who you serve.",
"sameAs": [ ]
}
The @id value is a fragment URI. It does not need to resolve to a real page. It is a unique identifier within the graph that other nodes use to reference this entity. I use the pattern https://yoursite.com/#person because it is stable and readable.
The sameAs array is the single most underused schema property I see on client sites. It is also one of the most important for AI search. This is where you tell search engines and AI crawlers that the same entity exists on LinkedIn, Upwork, X, Wikidata, GitHub, and anywhere else you have a verified presence.
Why does this matter? Because entity disambiguation is one of the hardest problems AI engines face. When ChatGPT encounters a name, it needs to figure out which person or company that name refers to. The sameAs array gives it a map of confirmed identities to cross-reference.
"sameAs": [ "https://www.linkedin.com/in/your-profile/", "https://www.upwork.com/freelancers/your-profile", "https://x.com/your-handle", "https://www.wikidata.org/wiki/Q-your-id", "https://github.com/your-username", "https://your-agency.com/" ]
Only include URLs where you have an active, verified profile. Do not fabricate Wikidata QIDs or add platforms you are not actually on. AI engines and Google both check whether the linked profiles actually exist and whether they reference the same entity. Fake sameAs links are a spam signal, not a shortcut.
Every page needs a schema type that describes what the content is. For a blog post, that is BlogPosting. For a services page, that is Service. For a product page, Product. For a how-to guide, you can use either Article or BlogPosting as the primary type and add a separate HowTo node for the steps.
The key is connecting the page type back to the Person or Organization using @id references. This is what tells AI engines that the author of this content is the same entity described in step 1.
{
"@type": "BlogPosting",
"@id": "https://yoursite.com/blog/your-post#article",
"headline": "Your Post Title",
"description": "Your meta description or a concise summary.",
"url": "https://yoursite.com/blog/your-post",
"image": "https://yoursite.com/blog/images/your-cover.webp",
"datePublished": "2026-07-17",
"dateModified": "2026-07-17",
"author": { "@id": "https://yoursite.com/#person" },
"publisher": { "@id": "https://yoursite.com/#person" },
"mainEntityOfPage": "https://yoursite.com/blog/your-post",
"inLanguage": "en",
"about": [
{ "@type": "Thing", "name": "Your Topic" }
]
}
Notice that author and publisher both use @id instead of embedding the full Person object again. This is what makes the graph a graph instead of a flat list. The engine reads the @id, looks up the Person node, and connects the two. The about array helps with topical classification, telling engines what subjects the content covers.
BreadcrumbList tells engines where a page sits in your site hierarchy. This matters for AI search because it reinforces topical clustering. If your breadcrumb trail shows Home, then Blog, then your post title, the engine understands that this page is part of a broader content hub, not an orphaned article.
{
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://yoursite.com/" },
{ "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://yoursite.com/blog" },
{ "@type": "ListItem", "position": 3, "name": "Your Post Title", "item": "https://yoursite.com/blog/your-post" }
]
}
The BreadcrumbList in the schema must match the visible breadcrumb trail on the page. If the trail on screen says Home, Blog, Post Title, the schema must say the same thing in the same order. Mismatches between schema and visible content are exactly the kind of inconsistency that can get flagged.
If your page has a visible FAQ section with real questions and answers, add a FAQPage node. This is still eligible for rich results in Google Search, and it gives AI engines pre-structured question-answer pairs they can pull directly into their responses.
{
"@type": "FAQPage",
"@id": "https://yoursite.com/blog/your-post#faq",
"mainEntity": [
{
"@type": "Question",
"name": "Your question exactly as it appears on the page?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Your answer exactly as it appears on the page."
}
}
]
}
The honesty rule. Every question in the schema must exist word-for-word on the visible page. Every answer in the schema must match the visible answer. If you add FAQ schema for questions that only exist in the code, that is a structured data violation. Google has gotten stricter about this, and fabricated schema data is a spam risk, not an optimization.
If the page is a step-by-step walkthrough, add a HowTo node. If it is a listicle or ranking, add an ItemList. These are bonus nodes that provide additional structure, but only when the content genuinely matches the type.
A HowTo node lists each step with a name and description. You can also include totalTime, tools, and images per step. This is especially useful for guides like setting up AI traffic tracking in GA4 or auditing content for answer engine readiness, where the steps are the core value of the page.
{
"@type": "HowTo",
"@id": "https://yoursite.com/blog/your-post#howto",
"name": "How to Do the Thing This Post Teaches",
"totalTime": "PT30M",
"step": [
{
"@type": "HowToStep",
"position": 1,
"name": "First step name",
"text": "Description of the first step."
}
]
}
For listicles, ItemList works the same way, with each item in the list getting a position and a name. I use this on pages like the top AI SEO experts in India roundup, where the ranking order is part of the content's value.
Before publishing, run three checks. First, paste the page URL into Google Rich Results Test and confirm every schema type is detected and eligible. Second, use the Schema.org Validator for strict syntax checking. Third, manually verify that every @id reference resolves to another node within the same @graph block.
I also run a programmatic check on every page I build. The script validates that the JSON-LD parses cleanly, that no em dashes or emojis leaked into the schema text, and that the headline and description in the schema match the visible title and meta description on the page. This catches the subtle mismatches that manual checking misses.
If you use a static site generator or build pipeline, bake the validation into the build step. If the schema fails, the page should not deploy. This is the quality gate that prevents broken structured data from reaching production.
The Assembled @graph: How It All Connects
Here is the full structure with every node wired together. This is a simplified version of the exact pattern I use on this site.
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://yoursite.com/#person",
"name": "Your Name",
"sameAs": ["linkedin", "upwork", "x", "wikidata"]
},
{
"@type": "BlogPosting",
"author": { "@id": "https://yoursite.com/#person" },
"publisher": { "@id": "https://yoursite.com/#person" }
},
{
"@type": "BreadcrumbList",
"itemListElement": [...]
},
{
"@type": "FAQPage",
"mainEntity": [...]
},
{
"@type": "HowTo",
"step": [...]
}
]
}
Every node serves a purpose. Person handles entity identity. BlogPosting handles content attribution. BreadcrumbList handles site hierarchy. FAQPage handles pre-structured Q&A. HowTo handles procedural content. Together they give an AI engine everything it needs to understand who you are, what this page is, and whether to trust it enough to cite.
Schema Types by Page Type
| Page type | Primary schema | Additional nodes |
|---|---|---|
| Blog post | BlogPosting | Person, BreadcrumbList, FAQPage, HowTo (if step-by-step) |
| Services page | Service | Person or Organization, BreadcrumbList, FAQPage |
| Product page | Product | Organization, BreadcrumbList, FAQPage, Review (if real reviews exist) |
| Local business | LocalBusiness | Organization, BreadcrumbList, FAQPage, GeoCoordinates |
| Listicle or roundup | BlogPosting | Person, BreadcrumbList, ItemList, FAQPage |
| How-to guide | BlogPosting or Article | Person, BreadcrumbList, HowTo, FAQPage |
| About page | AboutPage | Person or Organization, BreadcrumbList |
For local businesses specifically, the schema layering gets more detailed. I wrote a separate guide covering schema markup for local business SEO that walks through LocalBusiness, GeoCoordinates, and opening hours in the same @graph format.
Common Mistakes That Break the Graph
After auditing schema on hundreds of client sites, these are the issues I see most often.
Fabricating sameAs links. Adding a Wikidata QID you do not actually have, or linking to profiles that do not exist. This is not just unhelpful, it is a spam signal. Only include URLs where you have an active, verified presence.
Embedding full objects instead of using @id. If you copy the entire Person object into the author field of every BlogPosting, you are telling the engine these might be different people who happen to share the same name. Use @id references to make the connection explicit.
Schema without visible content. Adding FAQPage markup for questions that do not appear anywhere on the page. Adding HowTo steps that do not match visible instructions. Adding Review schema for reviews that do not exist on the page. All of these are structured data violations.
Mismatched dates. Setting datePublished to a date in the future, or leaving dateModified unchanged after a major content update. AI engines factor freshness into citation decisions, and how AI search processes intent includes evaluating whether the source is current.
Missing @id on the Person node. Without an @id, other nodes cannot reference the Person. The graph becomes a flat list of disconnected objects instead of a connected entity picture.
Schema and the Bigger AI Visibility Stack
Schema is foundational, but it is not the whole picture. It sits inside a larger stack that includes crawl access, content structure, entity signals, and off-site corroboration. Here is how the pieces fit together.
| Layer | What it does | Where to start |
|---|---|---|
| Crawl access | Lets AI crawlers find and read your content | llms.txt guide |
| Schema and entity clarity | Tells AI engines who you are and what the content covers | This guide |
| Content structure | Formats content so AI engines can extract answers | AEO readiness audit |
| AI traffic measurement | Shows which AI engines cite you and how that traffic converts | AI traffic tracking in GA4 |
| Off-site corroboration | Builds the external mentions that AI engines cross-reference | Claude SEO guide |
Schema without crawl access means the engine never sees your structured data. Content structure without schema means the engine sees the content but cannot confirm who created it. The stack works best when every layer is in place.
Frequently Asked Questions
Getting Started
Start with the Person or Organization node and the sameAs array. That is the single highest-impact step you can take for AI search visibility, and it applies to every page on your site. Then add the page-level type and BreadcrumbList. Then layer in FAQPage and HowTo where the content supports it. Build outward from the identity anchor.
If you want to see every node in action, view the source on any page on this site. The schema graph on this very page includes Person, BlogPosting, HowTo, FAQPage, and BreadcrumbList, all connected through @id references. That is the standard I hold every client site to.
If you want this built on your site, or you need a full AEO readiness audit that includes schema as one layer of a broader AI visibility strategy, you can reach me on Upwork, connect on LinkedIn, or visit The Digital Geek for agency-level engagements.