SEO Phase 3/4 + fix broken Holders queries shipped in #226 - #227
Merged
Conversation
…de-template top pages
Phase 3 of the Ahrefs remediation. Every indexable page now passes both length
checks: 0 of 573 sitemap pages have a title over 60 chars or a description over
160 (previously 21 and 5).
Titles
- Adopted Google's own framing on the three pages where it discarded ours and
synthesised a better one: Orca DEX API, Four Meme API, Aerodrome Finance API.
The last also fixes a plain bug -- the title read "Base Aerodrome Base API".
- Shortened two over-length titles: robinhood-transactions-receipts-api (71 ->
37 frontmatter chars) and robinhood-token-holders-api (61 -> 53).
- Did NOT adopt the other ten SERP rewrites. Those are cases where Google
stripped our chain prefix ("Ethereum Uniswap API" -> "Uniswap API") for a
single query in a single country. Deleting a real qualifier on that evidence
risks more than it gains, and those titles were already well within limits.
New plugin: plugins/title-suffix-trim.js
Docusaurus composes <title> as `${frontMatter.title} | ${siteConfig.title}` with
no per-page opt-out. That suffix costs exactly 16 chars, so a frontmatter title
must be <=44 to render under 60 -- which would mean deleting keywords purely to
make room for branding. Branding is staying as "Bitquery Docs", so this postBuild
pass drops the suffix only from titles that render over 60 chars. Trims 175 of
1050 built titles. Deliberately narrow: <title> only (og:title and twitter:title
keep the full branded form, which is what social cards should show), only the
exact suffix, and never leaves an empty title.
Descriptions
- Trimmed the 4 over 160: three Robinhood pages and the homepage.
- Hand-wrote 15 descriptions for the highest-traffic pages that still carried a
templated one, each grounded in that page's actual sections rather than
boilerplate. Prioritised by real traffic from Ahrefs top-pages rather than
guesswork: solana-photon-api (102), Solana-Raydium-DEX-API (38), intro (20),
pancake-swap-api (16), token-supply-cube, token-holder-api, internal-
transactions, Solana-DexPools, base-dextrades, OpenBook, Phoenix, Lifinity,
matic-balance-api, sunswap-api, uniswap-api.
- Rewrote two generated-index descriptions that were under 110: the Crypto Price
API and Metrics hubs (both have explicit slugs, so unlike /docs/category/*
auto-slugs they are intentional hub URLs).
- Fixed a 167-char description introduced in the previous commit.
Scale correction: the templated-description problem is larger than earlier
reported. A narrower regex counted only 3 of the 8 boilerplate tails and gave
145. The true figure was 282 files carrying `description: "<exact title>: <one
of ~8 tails>"`; 267 remain. Ahrefs never flags these because each passes the
length check individually.
Left alone deliberately:
- docs/chinese.md (42 chars): 42 CJK characters carry far more meaning than 42
Latin ones. Ahrefs' character rule miscounts CJK.
- 34 /docs/category/* stubs: verified to rank for exactly one zero-volume
keyword across all 34.
- Three pages at 104-109 chars: marginally under an arbitrary threshold and not
flagged by Ahrefs. Not padding for a counter.
- 26 pages still over 60 chars after trimming are all /docs/graphql-reference/,
which is Disallow'd in robots.txt and excluded from the sitemap.
Phase 4 deliverable is V1_DOCS_SEO_HANDOFF.md, gitignored alongside
v1_to_v2_plan.md per this repo's convention for internal planning docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Self-audit of the previous commit's TokenHolders -> Holders migration. I claimed
16 sites migrated having executed only one of them. Running the rest showed 7
failures: the migration renamed the cube and rewrote its arguments but left
selection sets and arguments that do not exist on Holders.
Fixed:
- `snapshot:` -> `date:` (pepe-api). Holders accepts only where / orderBy /
limitBy / limit / date.
- `BalanceUpdate { ... }` selection sets removed from Holders blocks
(rwa-api, stablecoin-payments-api x3, ai-agent-base-data). That sub-object
belongs to the old TokenHolders cube. Mapped the fields that have an
equivalent -- Count -> UpdateCount, FirstDate -> FirstChangeTime,
LastDate -> LastChangeTime -- and merged them into the existing Balance block.
- InCount / OutCount / InAmount / OutAmount have NO equivalent on Holders, so
they are gone. Two prose claims promised exactly that data ("including
inflows, outflows", "in/out counts"), so both now say what the query actually
returns and point at the Transfers cube for directional totals.
- Stale prose telling readers to "change the `snapshot` date".
These queries were already broken before the migration, since TokenHolders
itself fails on both realtime and archive -- so nothing working regressed. But
they were left broken while looking migrated, which is worse than leaving the
deprecation visible.
Audit results on the rest of the change set:
- 44 true Holders( call sites, 0 remaining invalid arguments or unknown fields.
- 573/573 indexable pages carry og:type and og:site_name.
- 0 duplicate titles and 0 duplicate meta descriptions among the 573.
- 0 titles over 60 chars and 0 descriptions over 160 in the sitemap.
- No Solana BalanceUpdates line was touched (verified against the diff);
Solana has no Balances cube and its BalanceUpdates is not deprecated.
- Pumpfun cluster: 22 distinct keywords, none claimed by two pages.
- No http:// internal links reintroduced; alt text intact on all 4 images.
- The API token never entered tracked files or commit history.
- title-suffix-trim does not desync JSON-LD: tech-article-jsonld derives
headline from frontmatter, so it now matches the trimmed <title> exactly.
Verification limit: further execution checks are blocked -- this session
exhausted the account's query points, so 36 extracted Holders queries could not
be re-run. The two confirmed defect classes were verified fixed by targeted
parsing instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Second formatting defect from the same repair script: it merged adjacent
Balance blocks but not `}Holder {`, leaving the closing brace jammed against
the next field. Valid GraphQL (whitespace is insignificant) but wrong in
generated docs. Reordered to Holder then Balance.
Also noted while showing the diffs: both TokenHolders sites in pepe-api.md sit
inside an HTML-commented region (lines 681-800 of 6 such regions), so those two
of the sixteen are not reader-visible. Live migrations are 14, not 16.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Follow-up to #226 (merged). Three commits that were not included in it.
Read the first section before merging — this PR repairs queries that #226 already shipped to
main.🔴 Fixes defects already live in main
2a583a0c(merged via #226) migrated 16TokenHolders→Holderssites. That commit's message claimed the migration was verified; in fact only 1 of the 16 had been executed. Running the rest afterwards showed 7 failures — the migration renamed the cube and rewrote its arguments but left selection sets and arguments that do not exist onHolders.snapshot:argumentpepe-apidate:.Holdersaccepts onlywhere/orderBy/limitBy/limit/date.BalanceUpdate { … }selection setrwa-api,stablecoin-payments-api×3,ai-agent-base-dataTokenHolderscube. MappedCount→UpdateCount,FirstDate→FirstChangeTime,LastDate→LastChangeTimeand merged into the existingBalanceblock.InCount/OutCount/InAmount/OutAmountHoldersequivalent. Removed.}Balance {and}Holder {stablecoin-payments-api,rwa-apipepe-apisnapshotdate".Two prose claims were over-promising. They advertised "including inflows, outflows" and "in/out counts" — precisely the fields with no
Holdersequivalent. Both now state what the query actually returns and point at the Transfers cube for directional totals.Mitigating context: these queries were already dead before the migration, because
EVM.TokenHoldersitself fails on both realtime (no table can query TokenHolder) and archive (Database eth does not exist). Nothing working regressed. But they were left broken while looking migrated, which is worse than leaving the deprecation visible.Also corrected: 2 of the 16 sites sit inside an HTML-commented region of
pepe-api.md(lines 681–800, one of 6 such regions), so they are not reader-visible. Live migrations are 14, not 16.Phase 3 — titles and descriptions
Every indexable page now passes both length checks:
Titles. Adopted Google's own framing on the three pages where it discarded ours and synthesised a better one (Orca, Four Meme, Aerodrome — the last also fixes a plain bug, the title read
Base Aerodrome Base API). Shortened the two genuinely over-length Robinhood titles.Did not adopt the other ten SERP rewrites: those are cases where Google stripped our chain prefix (
Ethereum Uniswap API→Uniswap API) for one query in one country. Deleting a real qualifier on that evidence risks more than it gains, and those titles were already well within limits.New plugin —
plugins/title-suffix-trim.js. Docusaurus composes<title>as${frontMatter.title} | ${siteConfig.title}with no per-page opt-out. That suffix costs exactly 16 chars, so a frontmatter title must be ≤44 to render under 60 — which would mean deleting keywords purely to make room for branding. Branding stays as "Bitquery Docs", so thispostBuildpass drops the suffix only from titles rendering over 60 chars. Trims 175 of 1050 built titles.Deliberately narrow:
<title>only —og:titleandtwitter:titlekeep the full branded form, which is what social cards should show. Only the exact suffix, anchored at the end. Never leaves an empty title. Verified it does not desync the JSON-LD:tech-article-jsonldderivesheadlinefrom frontmatter, so it now matches the trimmed<title>exactly.This turned out to be a dependency rather than a nice-to-have — enriching the three titles pushed them to 62/66/67 chars, so without the plugin the change would have traded one warning for another.
Descriptions. Trimmed the 4 over 160. Hand-wrote 15 for the highest-traffic pages still carrying a templated description, each grounded in that page's actual sections rather than boilerplate, prioritised by real Ahrefs traffic rather than guesswork. Rewrote two
generated-indexdescriptions under 110 (Crypto Price API and Metrics hubs — both have explicit slugs, so unlike/docs/category/*auto-slugs they are intentional hub URLs).Scale correction. The templated-description problem is larger than previously reported. An earlier regex covered only 3 of the 8 boilerplate tails and gave 145. The true figure was 282 files carrying
description: "<exact title>: <one of ~8 tails>"; 267 remain. Ahrefs never flags these because each passes the length check individually.Left alone deliberately:
docs/chinese.md(42 CJK characters carry far more than 42 Latin ones — Ahrefs' character rule miscounts CJK) · 34/docs/category/*stubs (verified to rank for exactly one zero-volume keyword across all 34) · three pages at 104–109 chars (marginally under an arbitrary threshold, not flagged by Ahrefs, not padding for a counter) · 26 pages still over 60 after trimming, all/docs/graphql-reference/, which isDisallowed in robots.txt and excluded from the sitemap.Phase 4 — V1 handoff
Deliverable is
V1_DOCS_SEO_HANDOFF.md, gitignored alongsidev1_to_v2_plan.mdper this repo's convention for internal planning docs. All findings verified live./v1/**pages emitcanonical → /v1/. Verified across 5 unrelated pages — identical tag. Self-inflicted de-indexing of the entire legacy set./v1/sitemap.xml(409 URLs) undeclared in robots.txt;/v1/has 624 internal inlinks but 0 entries in the main sitemap;/v1/blogis listed yet returns 301.gtag.jsforG-ZWB80TDH9JandGTM-5GC69JH6; V2 loads only GTM. Any V1-vs-V2 traffic comparison is ~2× wrong on the V1 side.Includes a sequencing constraint (do not declare the V1 sitemap until P0 lands, or we advertise 409 de-indexed URLs), a 5-point verification checklist with a runnable one-liner, and the tax-calculator defects.
Verification
yarn buildpasses; build output confirmed to reflect the changes, not a cache hitscripts/check-links.mjs: no link errors (533 pages, 1295 routes, strict)Holders(call sites, 0 remaining invalid arguments or unknown fieldsog:typeandog:site_nameBalanceUpdatesline was touched — verified against the diff. Solana has noBalancescube and itsBalanceUpdatesis not deprecated.Verification limit, stated plainly: this session exhausted the account's API query points, so 36 extracted
Holdersqueries could not be re-executed. 13 of the 20 run before the quota died passed; the two confirmed defect classes were verified fixed by targeted parsing rather than execution. Worth re-running when points reset — note thetoken-holder-api.mdxsites target USDT, which hits the large-token timeout documented indocs/cubes/balances-cube.mdand may need a balance floor to return at all.Needs an owner outside this PR
EVM.BalanceUpdates("removed 15 June 2026") andTron.BalanceUpdates("removed 18 July 2026") both still execute —EVM.BalanceUpdatesreturned data stamped2026-07-30T11:38:59Z. The notices are right aboutTokenHoldersand wrong about bothBalanceUpdatesvariants. Not edited, because only the API team can say whether removal was reverted, delayed, or the notices were written ahead of a plan.Tron.Holdersaggregate statistics return wrong values —sum(of: Balance_Amount)andmedianboth0for a token whose top holder holds 18M. The equivalent EVM query is correct (verified on PEPE:total / holdersmatchedaverageexactly). Tron-specific; deliberately undocumented until confirmed.pepe-api.mdhas 6 HTML-commented regions (170–265, 309–351, 353–392, 502–548, 610–651, 681–800) — a large share of an indexable page sitting dead. Someone should decide restore vs delete.robots.txt→/v1/sitemap.xmlis ready but blocked on V1 P0.🤖 Generated with Claude Code