What Is Schemamap and How Do You Implement It in 2026?
A schemamap points agents straight at your structured data, so a retrieval system reads one index and a handful of endpoints instead of crawling every URL to pull JSON-LD out of the HTML. This page gives you three working ways to publish one and the production details that decide whether consumers can actually use it.
Schemamap (schema mapping for agents) is the practice of publishing your site's structured data as its own retrievable resource, indexed at a known location, instead of leaving agents to lift it out of your HTML page by page. The index lists either one JSON-LD endpoint per resource or a small set of aggregated feeds; an agent fetches the index once and then pulls the graphs directly. It is aimed at database-backed sites, where the schema.org graph is the cheapest complete description of the catalogue you can hand over.
Two unrelated things share the name and are not what this page is about. Schemamap.io is a commercial batch data-import product for Postgres, with no connection to web publishing. schema-map in the UCP toolchain is the JSON Schema composition step in the ucp-schema CLI, a build-time operation on capability schemas rather than something a site publishes. The web convention below is the one that matters for AI visibility, and the one Glippy checks for.
Why Schemamap matters for AI visibility
Answer engines and natural-language retrieval systems treat schema.org markup as the highest-confidence machine description of a page. Getting all of it today means crawling every URL, rendering or parsing the HTML, and pulling one <script type="application/ld+json"> block at a time. The Schema Feeds draft names the four costs of that directly: it is computationally expensive on both sides, changes are only discovered on the next re-crawl, crawlers miss pages so the picture is incomplete, and the whole page is transferred to retrieve a fraction of it. A schemamap collapses the same job into one index fetch plus a few feed fetches, which for a 50,000 SKU catalogue is the difference between 50,000 HTML retrievals and a few gzipped files.
Be clear about the status before you plan around it. There is no ratified standard here, rel="schemamap" is not an IANA-registered link relation, and the Schemamap: line is not part of RFC 9309. Two incompatible file shapes are circulating under the same name, and this page covers both. What makes it worth shipping anyway is that it is additive and cheap: nothing breaks if no consumer reads it, and it already has a real install base, because Yoast SEO 27.1 shipped Schema Aggregation in March 2026, built with R.V. Guha and the NLWeb project, and yoast.com publishes a live Schemamap: directive today. If your JSON-LD is already correct, publishing it as a feed is a build step rather than a redesign.
Where the spec lives
One draft specification, one competing convention, one shipping implementation you can read the output of, and the two older formats both borrow from.
- Schema Feeds Specification v0.1 (draft, January 2026) - the primary source for the robots.txt
schemamapdirective, the sitemap-shaped Schema Map, and the JSON Lines feed format. Read this first if you are publishing a large catalogue. - The Website Specification: Schemamap - the competing convention: a
/schemamap.xmlindex of per-resource.jsonldendpoints, with a live worked example served from the same site. - Yoast Schema Aggregator API reference - exact endpoint paths, page sizes, cache headers and PHP filters for the shipping WordPress implementation. Useful even if you are not on WordPress, as a model of what to expose.
- Yoast SEO 27.1 release note - what shipped, when, and the NLWeb collaboration behind it. This is your evidence that the convention has a consumer, not just a proposal.
- Sitemaps XML protocol - the
urlsetandsitemapindexshapes the Schema Map reuses verbatim, including thelastmoddate rules. - JSON Lines - the one-object-per-line format required for
structuredData/schema.orgfeeds. Reach for it when your feed is too big to hold in memory.
Three ways to implement Schemamap
The three approaches differ by where the file comes from, not by what it says. A hand-written index suits a small documentation or brochure site with a few dozen pages. A build step suits any static site generator, and is the only one of the three that structurally cannot drift from the HTML you ship. The WordPress route suits anyone already running Yoast, and is the fastest way to get a real feed live, because the aggregation and paging are already written.
Static index of per-resource JSON-LD endpoints
Use this when you have tens of pages rather than tens of thousands, and each page already carries a JSON-LD graph. You publish a sibling .jsonld file next to each page, then list them all in one index at the site root. The XML namespace URI is site-defined, because no registry exists for it yet; use your own origin and keep it stable.
<?xml version="1.0" encoding="UTF-8"?>
<schemamap xmlns="https://example.com/schemas/schemamap/0.1">
<resource>
<loc>https://example.com/guides/agent-readiness/</loc>
<jsonld>https://example.com/guides/agent-readiness.jsonld</jsonld>
<type>TechArticle</type>
<type>BreadcrumbList</type>
<lastmod>2026-08-19T00:00:00.000Z</lastmod>
</resource>
<resource>
<loc>https://example.com/products/sku-001/</loc>
<jsonld>https://example.com/products/sku-001.jsonld</jsonld>
<type>Product</type>
<type>Offer</type>
<lastmod>2026-08-25T00:00:00.000Z</lastmod>
</resource>
</schemamap>
What this does: an agent reads the index once, sees which schema.org types each URL carries, and fetches only the graphs it cares about. Pair it with two head links so consumers that never request the root file still find it: <link rel="schemamap" type="application/xml" href="/schemamap.xml"> site-wide, and <link rel="alternate" type="application/ld+json" href="/guides/agent-readiness.jsonld"> on each page that has an endpoint.
Generate the index and endpoints from your build output
Use this on any static site generator. The script runs after your normal build, lifts the JSON-LD graph out of every page it already produced, writes the sibling endpoint, and emits the index. Deriving both from the same rendered HTML is what stops the feed and the page disagreeing, which is the failure mode consumers punish hardest.
import { readdir, readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
const DIST = 'dist';
const SITE = 'https://example.com';
const LD = /<script[^>]+application\/ld\+json[^>]*>([\s\S]*?)<\/script>/i;
const files = await readdir(DIST, { recursive: true });
const resources = [];
for (const file of files.filter((f) => f.endsWith('index.html'))) {
const found = (await readFile(join(DIST, file), 'utf8')).match(LD);
if (!found) continue;
const graph = JSON.parse(found[1]);
const dir = file.replace(/index\.html$/, '').replace(/\\/g, '/'); // '' or 'guides/foo/'
const stem = dir === '' ? 'index' : dir.slice(0, -1);
const nodes = Array.isArray(graph['@graph']) ? graph['@graph'] : [graph];
const types = [...new Set(nodes.map((n) => n['@type']).filter(Boolean))];
await writeFile(join(DIST, stem + '.jsonld'), JSON.stringify(graph, null, 2) + '\n');
resources.push({ loc: SITE + '/' + dir, jsonld: SITE + '/' + stem + '.jsonld', types });
}
resources.sort((a, b) => a.loc.localeCompare(b.loc));
const body = resources.map((r) => ' <resource>\n' +
' <loc>' + r.loc + '</loc>\n' +
' <jsonld>' + r.jsonld + '</jsonld>\n' +
r.types.map((t) => ' <type>' + t + '</type>').join('\n') +
'\n </resource>').join('\n');
await writeFile(join(DIST, 'schemamap.xml'),
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<schemamap xmlns="' + SITE + '/schemas/schemamap/0.1">\n' + body + '\n</schemamap>\n');
console.log('schemamap.xml: ' + resources.length + ' resources');
What this does: every deploy regenerates the endpoints and the index together, so an agent can never fetch a .jsonld that contradicts the page it names. Add a host rule so .jsonld files are served as application/ld+json with Access-Control-Allow-Origin: *, or browser-side agents will be blocked from reading them.
WordPress: enable Yoast Schema Aggregation and advertise it
Use this if the site runs Yoast SEO 27.1 or later. The feature is off by default. Once on, it exposes a Schema Map at /wp-json/yoast/v1/schema-aggregator/get-xml and JSON Lines feeds at /wp-json/yoast/v1/schema-aggregator/get-schema/{post_type}, paged at 1,000 items for most types and 100 for heavier ones such as products. The plugin advertises the map with a Schemamap: line in robots.txt; the code below adds the head link it does not emit.
<?php
/**
* Plugin Name: Schemamap discovery
* Turns on the Yoast Schema Aggregator endpoint, narrows it to the post types
* that carry real schema.org data, and advertises it with a head link.
*/
add_action( 'admin_init', function () {
if ( class_exists( 'WPSEO_Options' ) ) {
WPSEO_Options::set( 'enable_schema_aggregation_endpoint', true );
}
} );
// Skip post types whose only markup is boilerplate WebPage and BreadcrumbList.
add_filter( 'wpseo_schema_aggregator_post_types', function ( $post_types ) {
return array_values( array_intersect( $post_types, array( 'post', 'page', 'product' ) ) );
} );
// Advertise the Schema Map to consumers that read link relations, not robots.txt.
add_action( 'wp_head', function () {
printf(
'<link rel="schemamap" type="application/xml" title="Schemamap index" href="%s">' . "\n",
esc_url( rest_url( 'yoast/v1/schema-aggregator/get-xml' ) )
);
}, 1 );
What this does: it gives you a working feed without writing an aggregator, then makes it discoverable three ways instead of one, which matters because consumers disagree about where to look. Yoast serves each feed as JSON Lines with Cache-Control: public, max-age=300 and invalidates its own cache when a post is saved, so you do not need a separate rebuild trigger.
Implementation guidelines
These are the details that decide whether a schemamap is usable in production rather than merely present.
- Generate the feed from the source the page uses. The Schema Feeds draft states that feed data MUST be consistent with the markup on the corresponding HTML page, and warns that some consumers will trust in-page markup more. Derive both from one template or one query, never maintain them separately.
- Advertise it three ways. A
Schemamap:line in robots.txt with an absolute HTTPS URL, a<link rel="schemamap">in the head, and the file itself at/schemamap.xmlif you can. Consumers implement different subsets, and each route costs you one line. - Handle both shapes of contentType. The draft defines
<sf:contentType>as a child element in thesfnamespace, while Yoast ships it as acontentTypeattribute on<url>. Emit the child element for spec conformance, and tolerate the attribute when you consume someone else's map. - Set the response headers deliberately. Serve
.jsonldasapplication/ld+json; charset=utf-8, JSON Lines feeds asapplication/x-jsonlinesorapplication/json, and addAccess-Control-Allow-Origin: *to both. Without CORS a browser-resident agent cannot read the file at all, however correct it is. - Put a real lastmod on every entry. Use W3C datetime format and update it when the underlying content changes, so consumers can skip unchanged feeds. Support
If-Modified-Sinceas well, since the draft tells consumers to send it. - Split by type, then page, then compress. One feed per content type keeps a product change from invalidating your article feed. Page long feeds the way Yoast does, and gzip anything large, serving it with a
.jsonl.gzextension as the draft recommends. - Treat the feed as published output. Everything in it is public in bulk, without the rate limiting that page-by-page crawling imposes. Exclude drafts, private post types, noindex URLs and internal-only fields before you generate, not afterwards.
Do this, not that
Do
- Give every node a stable
@idthat matches the canonical URL of the page it describes, so agents can reconcile the feed against your HTML. - Write
Schemamap: https://example.com/schemamap.xmlin robots.txt as an absolute HTTPS URL, on its own line, alongside your existingSitemap:line. - Keep the
.jsonldbody byte-identical to the in-page<script type="application/ld+json">graph after sorting keys, and assert that in CI. - Verify that every
<loc>in the index returns HTTP 200 before you ship, then re-verify on every deploy.
Do not
- Do not put anything in the feed that the page does not say. A single fabricated
@typeor price gives a consumer reason to discard the whole feed. - Do not list resources whose only markup is a site-wide
WebSiteandBreadcrumbList; that is boilerplate, and it dilutes the index. - Do not treat the schemamap as a replacement for
sitemap.xml,llms.txt, or the JSON-LD in your HTML. It is an additional surface, and the others still carry traffic. - Do not serve
.jsonldastext/html, behind authentication, or without CORS headers, all of which make it unreadable to the agents it exists for.
How Glippy checks this
Glippy scores schemamap under Agent Interactivity (category 10), alongside the other agent discovery surfaces such as the MCP server card, the A2A agent card and NLWeb. It requests /schemamap.xml from the site root and passes the check if the response contains a <schemamap> root or <resource> entries, reporting how many resources it counted. It also reads <link rel="schemamap" href="..."> from the page head independently, which is how a sitemap-shaped feed index or a map served from a non-root path such as a WordPress REST route gets credit. This is a bonus signal: publishing one lifts the category score, and not publishing one is reported as information without a penalty. The full breakdown is on the AI agent accessibility checker page.
Check your Schemamap setup
Glippy runs 240+ checks across 16 categories on any page, including Agent Interactivity (category 10). No sign-up required.
Frequently asked questions
No. The Schema Feeds specification that defines the robots.txt schemamap directive is a version 0.1 draft dated January 2026 with no standards body behind it, rel="schemamap" is not registered with IANA, and the directive is not part of RFC 9309. It does have a shipping implementation, since Yoast SEO 27.1 released Schema Aggregation in March 2026 built with the NLWeb project. Treat it as an additive bonus surface rather than infrastructure you depend on.
A sitemap lists URLs so a crawler knows which pages exist and when they changed; the crawler still has to fetch and parse each one. A schemamap lists structured-data resources, so a consumer can retrieve the schema.org graph without fetching the pages at all. They serve different consumers and different purposes, and the two files can be advertised side by side in robots.txt with a Sitemap: line and a Schemamap: line. Publish both.
Yes. Search engines and AI answer engines read the in-page markup, and the Schema Feeds draft is explicit that some consumers will not extend the same level of trust to feed data as to markup extracted from the page itself. The feed is an efficiency layer on top of correct in-page JSON-LD, not a substitute for it. Keep the two identical and generate them from the same source.
Pick by scale. Per-resource .jsonld endpoints listed in a <schemamap> index are simple and easy to verify, and suit sites in the tens or low hundreds of pages. Aggregated JSON Lines feeds listed in a sitemap-shaped index are what the Schema Feeds draft defines and what Yoast implements, and are the only practical option once you are past a few thousand resources. Both are advertised under the same name, so add a <link rel="schemamap"> tag whichever you choose.
Reviewed against the primary sources on . These standards move quickly, so check the linked specs before you ship.