You've read that schema markup helps AI engines understand your pages. Now you're staring at a few hundred URLs, trying to work out where to add schema markup and which pages even deserve it. That's exactly the right question, and almost nobody answers it clearly.
Here's what you'll have by the end: a decision for every page template on your site, the schema type that belongs on each, and the exact spot in the page where the markup should sit. Not theory. A map you can hand to a developer or paste into your CMS this week.
Good news before we start. Schema placement is one of the few parts of AI visibility with real, documented answers. Google has published where the markup can go. Schema.org has published what each type means. You're not guessing here, you're following a spec.
Start with templates, not pages
Take a breath. You are not going to decide this URL by URL.
Your site has a few hundred pages, but it probably has eight to twelve templates. A blog post template. A product detail template. A category page. An about page. A contact page. Maybe a careers listing and a location page.
Schema lives on the template. Decide once, and every page built from that template inherits it. That single shift is what makes schema placement tractable instead of endless.
So open a spreadsheet and list your templates in one column. In the next column, write how many URLs use each one. In the third, write the page's primary purpose in five words. That third column is the one that matters, because it decides the schema type in the next step.
How you know you're done: every URL on your site maps to exactly one template on your list. If you find pages that don't fit any template, those are your one-off pages (homepage, about, contact), and they each count as their own template.
Where people go wrong: they start with a schema type they read about and hunt for pages to put it on. That's backwards. The page's purpose picks the schema, never the other way around.
If your sitemap is already classified by page type and topic, this step takes twenty minutes instead of an afternoon. DeepSmith's Sitemap module brings your published pages in and classifies each one by topic, type, angle, and buyer stage, so the template inventory is mostly built before you start. However you get there, you need the map before you write a single line of JSON-LD.
Match each template to its primary entity
Every page is "about" one thing. That thing is your primary entity, and it picks your schema type.
Here's the mapping that covers most sites. Work down your template list and assign one:
Homepage: Organization plus WebSite. Organization carries your name, url, logo, and sameAs (your social profile URLs). WebSite carries name, url, and a potentialAction of type SearchAction if you want the sitelinks searchbox.
About page: Organization, extended. Add description, foundingDate, address, founder, numberOfEmployees, and areaServed.
Contact page: Organization with a contactPoint array (phone, email, contact type, languages). Use LocalBusiness only if customers actually come to a physical location.
Blog post: Article, or its subtypes BlogPosting for blog content, NewsArticle for news, Report for research. Required: headline, image, datePublished, dateModified, and author. Recommended: publisher, description, and mainEntityOfPage.
Product detail page: Product with name, image, description, sku, at least one identifier (gtin, mpn, or isbn), brand, and offers. The Offer carries price, priceCurrency, availability, and url.
Category or collection page: CollectionPage with an ItemList, or just a BreadcrumbList. Not Product. We'll come back to why.
FAQ page: FAQPage, but only when the page's whole purpose is a list of questions and answers.
Tutorial page: HowTo with a step array, where each step has a name and text.
Location page: LocalBusiness, using the most specific subtype that fits (Restaurant, LegalService, Dentist, AutoRepair, Store).
Author profile: Person with name, jobTitle, url, image, worksFor, and sameAs.
Job listing: JobPosting with title, description, datePosted, validThrough, employmentType, hiringOrganization, and jobLocation.
Service page: Service with name, serviceType, description, provider, and areaServed.
Event page: Event with name, startDate, endDate, location, and organizer.
Answering which pages need schema gets easier once you see it this way. If a template has a clear primary entity in that list, it needs schema. If you can't name the entity, it probably doesn't.
A note on Article subtypes, since this trips people up. BlogPosting for blog posts, NewsArticle for news content, Report for research and investigative pieces, and plain Article when none of those fit. Picking a subtype isn't a ranking lever. It's a precision signal, and precision is the whole point.
Same logic on LocalBusiness. If a specific subtype exists for what you do, use it. Restaurant beats LocalBusiness. Dentist beats LocalBusiness. Generic types describe you vaguely, and vague is the opposite of what you're going for.
How you know you're done: every template on your list has exactly one primary entity written next to it, and you could defend each choice by pointing at what's visible on the page.
Pro tip: one primary entity per page is the convention, but multiple entities on a page are completely fine. A blog post can carry Article, BreadcrumbList, and a reference to Organization all at once. That's normal and expected.
Split your markup into site-wide and page-level
This is the decision that turns a pile of schema into a site-wide schema strategy.
The question to ask on every template: is this claim true on every single page, or only on some of them? A site-wide schema strategy works because it separates the two cleanly, and it falls apart the moment you blur them.
Some schema belongs in your global header or footer template, so it renders on every page:
- Organization. Define it once. Every other page points back to it.
- BreadcrumbList. Generated from the URL hierarchy, so it works anywhere breadcrumbs are visible.
- WebSite with SearchAction. Usually the homepage, though site-wide is acceptable.
Everything else is page-level and belongs only where the entity genuinely lives:
- Article only on individual posts.
- Product only on product detail pages.
- FAQPage only on real FAQ pages.
- HowTo only on genuine step-by-step tutorials.
- JobPosting only on individual job pages, never the careers index.
- LocalBusiness only on location pages.
- Event only on event detail pages.
- Recipe only on recipes, Course only on course pages, VideoObject only where the video is the main content.
Where people go wrong: emitting Article schema site-wide. Somebody adds it to the global template, and suddenly your pricing page claims to be an article. It's thin, it's conflicting, and it teaches engines the wrong thing about your site.
Site-wide markup makes a claim on every page. Make sure the claim is true on every page.
Connect your entities with @id
This is the highest-leverage thing in the whole guide, and most sites skip it.
Define your Organization once, with an @id like https://example.com/#organization. Then on every article, instead of repeating the whole Organization object, you just point at it:
"publisher": {"@id": "https://example.com/#organization"}
Same with authors. Define Jane once at https://example.com/#author/jane-doe. Every article she writes references that @id.
Why does this matter so much? Because it builds one canonical entity graph instead of forty slightly different copies of your company. Engines follow the reference and resolve it to a single, consistent entity. That's exactly the clarity AI systems need to connect a brand to a topic.
There's a maintenance win too. Your logo URL changes, and you fix it in one place. Not on every page.
The clean way to hold multiple entities on one page is a single script with an @graph array:
{
"@context": "https://schema.org",
"@graph": [
{"@type":"Organization","@id":"https://example.com/#organization","name":"...","url":"...","logo":"..."},
{"@type":"WebSite","@id":"https://example.com/#website","name":"...","url":"..."},
{"@type":"BreadcrumbList","itemListElement":[]},
{"@type":"Article","headline":"...","author":{"@id":"https://example.com/#author/jane"},"publisher":{"@id":"https://example.com/#organization"}}
]
}
The alternative, multiple separate script blocks each holding one entity, is also valid. The @graph pattern is just cleaner to parse and avoids collisions when two entities both carry an @context.
Put the markup where crawlers actually read it
Now the question you came for: where in the page does the code go?
Let's settle schema in head or body first, because it's the thing people agonize over for no reason. Google states that JSON-LD can be embedded in either the head or the body of an HTML page. Schema.org has long said the same. Both work for rich results. Both work for AI crawlers parsing the rendered page.
So schema in head or body is a code-organization choice, not a visibility decision. If your CMS or plugin injects into the head, leave it. That's what Yoast, Rank Math, and Schema Pro do by default, and it's fine. If your developer prefers injecting near the closing body tag for caching or streaming reasons, that's equally fine.
The markup goes inside a script tag, like this:
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"Article","headline":"..."}
</script>
Your @context must be https://schema.org. The block must be valid JSON. A trailing comma will break the parser and silently cost you the whole block.
Here's the placement rule that actually matters, and it has nothing to do with head or body: the JSON-LD must be in the HTML that gets served, not injected later by JavaScript.
If your markup only appears after React hydrates, or after a tag manager fires, or after an AJAX call completes, you're gambling. Google's renderer can execute JavaScript. Many AI crawlers prefer pre-rendered HTML, and crawlers with limited rendering budgets may never see your markup at all.
The one-second test: view source on the page. Not inspect element, view source. If you can find your JSON-LD in that raw HTML, you're server-rendered and safe. If you have to open the rendered DOM to find it, it's client-only and at risk.
This is why we don't recommend injecting schema through a tag manager as your primary pattern. It's convenient, and it introduces exactly the render dependency you're trying to avoid.
Where people go wrong: the same schema gets injected twice, once by a plugin and once by a theme or a custom template. Duplicate blocks for the same entity are the most common self-inflicted wound here. Check for it after any plugin change.
Cut schema from the pages that shouldn't have it
Removing markup feels wrong. It's often the highest-value hour you'll spend.
Google's policy is blunt: don't mark up content that isn't visible to users. Your schema has to describe the page a human actually sees. Break that rule and you risk a manual action, and you'll quietly lose rich result eligibility either way.
Go find these four, because they're everywhere:
FAQPage on regular blog posts. A post that happens to answer two questions in the body isn't an FAQ page. The page's primary purpose has to be a list of questions and answers. This one is nearly universal, so check it first.
Product schema on category pages. A category page lists many products. It isn't "about" any single one. Use CollectionPage with an ItemList instead, or just BreadcrumbList.
AggregateRating with no visible rating. If there's no star widget on the page, the rating can't be in your schema. Full stop.
JobPosting on a careers index. The index links to jobs. It isn't a job. The markup belongs on each individual posting.
While you're in there, check for stale markup too: filled jobs, past events, old prices. Structured data that contradicts your page is worse than no structured data.
Where people go wrong: treating markup as free. Every schema block is a claim you're making to a machine. Wrong claims cost you more than missing ones.
Validate before you publish
Three tools, in this order. Don't skip to the third.
- Schema Markup Validator at validator.schema.org. Checks your markup against the Schema.org vocabulary. Catches typos in type and property names.
- Google Rich Results Test at search.google.com/test/rich-results. Checks eligibility for Google's specific features. This is the one that tells you whether Google will do anything with your markup.
- Search Console, Enhancements reports. Production monitoring, after indexing. This is your ongoing signal at scale.
Your pre-publish checklist, five items:
- Rich Results Test shows zero errors for the declared type.
- Schema Markup Validator shows zero errors.
- View source shows the JSON-LD in the served HTML.
- Every claim in the schema matches what's visible on the page (price, rating, questions, dates).
- Organization is referenced by @id from every Article, Product, and LocalBusiness page.
The errors that recur most: missing required properties, dates that aren't ISO 8601, prices without a currency, relative URLs where absolute ones belong, and image URLs that 404. None of them are hard. All of them are silent.
Keep placement honest as templates change
You're not done, and that's genuinely okay. Schema decays.
A developer ships a template change and the JSON-LD stops rendering. A plugin update starts injecting a second Organization block. A page gets rebuilt in a new framework and quietly goes client-side. None of it announces itself.
So put two habits in place:
Re-run the checklist on any template change. Not every page. Just one page per changed template, because the template is the unit.
Watch Search Console Enhancements weekly. It tells you which types are erroring and roughly where.
The thing neither tool tells you is whether the pages you marked up are the pages AI actually cites. That's a different question, and it's the one your leadership will ask. DeepSmith's AEO module tracks mention and citation rates across engines like ChatGPT, Perplexity, and Gemini, and its Pages view shows which of your pages get cited and for which prompts. Schema placement gets you eligible. Tracking tells you whether eligibility turned into visibility.
What to do next
Don't try to do all of this at once. Pick your two highest-traffic templates, usually the blog post and the product or service page. Get the primary entity right, confirm it's server-rendered, wire the publisher @id back to Organization, and validate.
That's a week of work at most, and it covers the majority of your indexed URLs. Then work down the template list.
You're closer than you think. Most sites already have markup. It's on the wrong pages, or it's making claims the page doesn't support, and fixing that is faster than starting from zero.
If you'd rather not hand-maintain this across every new page you publish, that's fair. Schema markup, heading structure, internal linking, and metadata are part of DeepSmith's writing pipeline, built in during creation instead of bolted on after. Start a free trial and see what your next article looks like when the markup ships with it.



