feat(seo): give the site one entity instead of one per page - #200
Closed
chaxus wants to merge 1 commit into
Closed
Conversation
Read apple.com's markup and took the part that transfers. Apple never
redefines "Apple": it names the node once as #organization and every page
after that writes manufacturer: { "@id": ... }. Same for #website and each
product's #brand.
We did the opposite. Every page emitted its own anonymous WebApplication and
SoftwareSourceCode, so 154 pages described 154 unrelated tools that happened
to share a name. That costs little in ranking and a lot in the machines that
answer questions about the site -- an assistant that reads three of our pages
should come away with one editor.
Organization, WebSite, WebApplication and SoftwareSourceCode now have fixed
@ids and appear on every page as references to each other; WebPage, FAQPage,
HowTo and BreadcrumbList get page-scoped ones. The app's url is the site root
everywhere -- a per-page url made each translation look like a separate
product -- and the language moved to WebPage.inLanguage, where it belongs,
with the app and site carrying the list of all seven.
A documentation page is a page about the editor, not a listing of it, so it
ships a named stub rather than the full node with price and category. It has
to ship something: about: { "@id": ... } pointing at nothing is dropped, and
the page goes back to describing an anonymous application.
Also from Apple: max-image-preview:large on every page (plus max-snippet:-1,
which is ours -- it lifts the cap on what a search or AI summary may quote),
and sameAs moved onto the Organization where it identifies the publisher.
Three new contracts run per page: this page's WebPage node is this page, any
WebApplication is the shared entity, and every @id reference resolves to a
definition in the same graph with no duplicate ids. That third one caught a
real dangling reference on the documentation pages, which is why appStub()
exists. Reverse-verified: stashing bin/build-pages.mjs turns 441 red.
Considered and rejected: hreflang pt -> pt-BR. Apple declares it because it
runs separate pt and br sites; we have one Portuguese, and narrowing it would
drop readers in Portugal to the English x-default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
chaxus
enabled auto-merge (rebase)
August 23, 2026 07:33
Deploying document with
|
| Latest commit: |
8562e72
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8a1c21ca.document-7hm.pages.dev |
| Branch Preview URL: | https://seo-entity-graph.document-7hm.pages.dev |
Contributor
Author
auto-merge was automatically disabled
August 23, 2026 07:45
Pull request was closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Read apple.com's markup and took the part that transfers. Apple never
redefines "Apple": it names the node once as #organization and every page
after that writes manufacturer: { "@id": ... }. Same for #website and each
product's #brand.
We did the opposite. Every page emitted its own anonymous WebApplication and
SoftwareSourceCode, so 154 pages described 154 unrelated tools that happened
to share a name. That costs little in ranking and a lot in the machines that
answer questions about the site -- an assistant that reads three of our pages
should come away with one editor.
Organization, WebSite, WebApplication and SoftwareSourceCode now have fixed
@ids and appear on every page as references to each other; WebPage, FAQPage,
HowTo and BreadcrumbList get page-scoped ones. The app's url is the site root
everywhere -- a per-page url made each translation look like a separate
product -- and the language moved to WebPage.inLanguage, where it belongs,
with the app and site carrying the list of all seven.
A documentation page is a page about the editor, not a listing of it, so it
ships a named stub rather than the full node with price and category. It has
to ship something: about: { "@id": ... } pointing at nothing is dropped, and
the page goes back to describing an anonymous application.
Also from Apple: max-image-preview:large on every page (plus max-snippet:-1,
which is ours -- it lifts the cap on what a search or AI summary may quote),
and sameAs moved onto the Organization where it identifies the publisher.
Three new contracts run per page: this page's WebPage node is this page, any
WebApplication is the shared entity, and every @id reference resolves to a
definition in the same graph with no duplicate ids. That third one caught a
real dangling reference on the documentation pages, which is why appStub()
exists. Reverse-verified: stashing bin/build-pages.mjs turns 441 red.
Considered and rejected: hreflang pt -> pt-BR. Apple declares it because it
runs separate pt and br sites; we have one Portuguese, and narrowing it would
drop readers in Portugal to the English x-default.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com