Skip to content

feat(seo): set the brand Organization entity via Mintlify's native seo.organization - #2285

Open
GigaHierz wants to merge 3 commits into
mainfrom
GigaHierz/2283-org-jsonld
Open

feat(seo): set the brand Organization entity via Mintlify's native seo.organization#2285
GigaHierz wants to merge 3 commits into
mainfrom
GigaHierz/2283-org-jsonld

Conversation

@GigaHierz

Copy link
Copy Markdown
Contributor

The hole, and the fix

Verified live today: Mintlify auto-injects an Organization schema named "Celo Docs" with no sameAs, plus a WebSite node crediting Mintlify as creator — the docs are disconnected from the Celo brand entity that search and AI engines resolve.

Adds seo-schema.js (Mintlify loads any content-directory .js on every page, no wiring needed) injecting one JSON-LD @graph: an Organization Celo (https://celo.org/#organization) with a sameAs array (GitHub org, X, YouTube, Discord, Forum, CoinGecko, DefiLlama, L2BEAT), and a WebSite node for docs.celo.org whose publisher points at that Organization — the docs→brand linkage the entity graph was missing.

What this does NOT do / residual risk

  • Client-side injection: the script runs after load. Google and DOM-rendering crawlers process it; plain-fetch crawlers see only Mintlify's static blocks. Static head injection is not available on the current plan — recorded in the file header.
  • Does not touch celo.org's own missing JSON-LD (Framer; tracked outside this repo) and cannot rename Mintlify's auto-generated "Celo Docs" nodes.
  • Duplicate-node risk is low: the injected @ids (celo.org/#organization, docs.celo.org/#celo-docs) differ from Mintlify's (docs.celo.org/#organization, docs.celo.org#website).

Judgement calls

  • sameAs list = the docs.json footer socials + the three data aggregators the entity graph needs (CoinGecko, DefiLlama, L2BEAT). Adding/removing an entry is a one-line change.
  • Logo reuses the docs logo asset; swap to a brand asset URL if marketing prefers.

Issues

Refs #2283 — closes the script box; the "verified on the preview deployment" box stays open until the Mintlify preview for this PR is up (checkbox below).

Stacking / conflicts

Branched off main, independent — new file only.

Verification evidence

# live, before this change:
$ curl -sL https://docs.celo.org/ | grep ld+json   # Organization name "Celo Docs", no sameAs; WebSite creator = Mintlify
# this branch:
$ node -e "…"    # script parses; the JSON-LD object serializes cleanly
$ mint broken-links   # on 8b7a63ef
success no broken links found

Every sameAs URL verified: five return 200 to curl; CoinGecko and DefiLlama return 403 to curl (Cloudflare bot-blocking) but their APIs confirm the slugs (api.coingecko.com/api/v3/coins/celo → id celo; api.llama.fi/v2/chains lists Celo); L2BEAT project page returns 200.

Remaining ops steps

  • Once the Mintlify preview deploys for this PR, open any page, run JSON.parse(document.querySelectorAll('script[type="application/ld+json"]')[last].text) in the console (or Google's Rich Results test) and tick this box

Checklist

  • Title is the commit message I want on main
  • Script syntax-checked; JSON-LD validated locally; all entity URLs verified
  • Known limitation (client-side injection) stated in file and above
  • No secrets in the diff

@GigaHierz
GigaHierz requested a review from a team as a code owner August 25, 2026 11:50
@GigaHierz
GigaHierz requested a review from palango August 25, 2026 11:50
@palango

palango commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Mintlify has a native seo.organization block in docs.json that does what this file does, server-side. Worth switching before this lands.

The schema lives at https://mintlify.com/docs.json, which docs.json line 2 already points $schema at:

"seo": { "organization": { "id", "name", "legalName", "url", "logo", "sameAs" } }

id defaults to <site origin>/#organization, and that is already the id in the live graph. curl -sL https://docs.celo.org/ | rg 'ld\+json' returns Organization{"@id":"https://docs.celo.org/#organization","name":"Celo Docs"} with no sameAs, and the page nodes point publisher at it. Nothing in that graph mentions celo.org/#organization or docs.celo.org/#celo-docs, and Google merges by @id, so the injected nodes sit beside the real graph instead of joining it. Being server-rendered, it also reaches the plain-fetch crawlers your header comment says will miss the block, which is the limitation you flagged yourself.

I checked this against the schema and the settings page rather than a deploy, so I cannot tell you whether it is plan-gated. Static head injection being unavailable is a separate feature.

Worth fixing whichever way you go:

  • Drop the WebSite node. Mintlify already emits one named "Celo Docs" for this URL, so a second named "Celo Documentation" hands Google two competing site names when it supports one.
  • The logo gets dropped for being too small. CeloDocs_LogoLight.svg is 343x50 against Google's 112x112 floor. logo/celo_light.png is already in the repo at 4034x913 and serves 200. That one predates your PR, since the undersized logo is already live.
  • The description is the third wording of the same claim, after docs.json and home/celo.mdx frontmatter.

Smaller: the Discord invite is revocable rather than a profile URL, forum.celo.org here against forum.celo.org/ in the footer, and sameAs restates footer.links and navbar with nothing keeping them in sync.

The branch is also behind main. #2279 and #2280 both rewrote docs.json.

GigaHierz and others added 3 commits August 28, 2026 13:58
…g docs to the Celo entity

Closes #2283

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Google's structured-data logo guideline requires a raster format; SVG is
ignored for the logo feature. Point at the Celo brand PNG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… JSON-LD

Replaces seo-schema.js with the `seo.organization` block in docs.json.

The injected script added a second Organization node at a different `@id`
(`https://celo.org/#organization`) than the one Mintlify already emits and
references from every page's `publisher` (`https://docs.celo.org/#organization`).
Google merges by `@id`, so the injected node sat beside the real graph instead
of joining it. The native block edits the existing node in place, is rendered
server-side, and so also reaches crawlers that do not execute JavaScript —
the limitation the deleted file documented in its own header comment.

Verified against https://mintlify.com/docs.json, which docs.json already
declares as its `$schema`: `seo.organization` accepts `id`, `name`, `legalName`,
`url`, `logo` and `sameAs`.

Other changes this forces or fixes:

- The `WebSite` node is gone. Mintlify already emits one named "Celo Docs" for
  this URL; a second named "Celo Documentation" gave Google two competing site
  names.
- `logo` now points at logo/celo_light.png (4034x913) rather than the docs logo
  CeloDocs_LogoLight.svg (343x50), which is below Google's 112x112 floor.
- The duplicated description is dropped; the schema has no description field,
  and the claim already appears in docs.json and home/celo.mdx frontmatter.
- `forum.celo.org/` now matches the trailing slash used in footer.links.
- `sameAs` is limited to official Celo profiles that were verified to return
  200. The CoinGecko and DefiLlama listings are dropped: both are third-party
  listings rather than official profiles, and both return 403 to any
  non-browser client, so the links cannot be checked.
- `id` is left at its default so it keeps matching the id the rest of the graph
  already points at. celo.org emits no JSON-LD at all today, so pointing it at
  `https://celo.org/#organization` would not merge with anything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@GigaHierz
GigaHierz force-pushed the GigaHierz/2283-org-jsonld branch from d04fc7a to 75e7699 Compare August 28, 2026 12:59
@GigaHierz

Copy link
Copy Markdown
Contributor Author

Switched to seo.organization, rebased on main. 75e7699c.

You were right on every point, and I confirmed the two claims I was relying on rather than assuming them.

The schema field exists. https://mintlify.com/docs.json (already this repo's $schema) has seo.organization with id, name, legalName, url, logo, sameAsadditionalProperties: false, no description field, which settles that point on its own.

The graph problem is real, and worse than "sits beside". The live page emits:

Organization @id https://docs.celo.org/#organization   name "Celo Docs"   (no sameAs)
WebSite      @id https://docs.celo.org#website         publisher -> the above

plus a separate Mintlify WebSite node. The injected file added an Organization at https://celo.org/#organization that nothing referenced, so the sameAs never attached to the node the pages actually point at.

One thing worth recording: celo.org emits no JSON-LD at allcurl -sL https://celo.org/ | grep ld+json returns zero blocks. So https://celo.org/#organization was not an existing entity to merge into. For that reason I left id at its default rather than overriding it: the default is the id the rest of the graph already references, and the brand linkage comes from url: https://celo.org plus sameAs. Happy to set it explicitly if you would rather stake the id now for when celo.org publishes a graph.

Everything else you flagged:

  • WebSite node dropped.
  • Logo → logo/celo_light.png. Confirmed 4034x913 from the PNG IHDR header, vs 343x50 for the SVG. Serves 200.
  • Description dropped (no field to put it in, which is the right answer anyway).
  • forum.celo.org/ now matches footer.links.
  • sameAs narrowed. I dropped CoinGecko and DefiLlama: they are third-party listings rather than official profiles, and both return 403 to any non-browser client, so a future reviewer cannot verify them. Remaining six all verified 200. I kept the Discord invite despite it being revocable, since it is the same link navbar.links and footer.links already use as the official community entry point — but say the word and it goes.

On sameAs drifting from footer.links and navbar: nothing keeps them in sync and I have not added anything that does. Worth its own issue if you want it enforced.

@GigaHierz GigaHierz changed the title feat(seo): inject brand-level Organization JSON-LD with sameAs linking docs to the Celo entity feat(seo): set the brand Organization entity via Mintlify's native seo.organization Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants