Skip to content

every outbound link says it came from here - #2753

Merged
Flotapponnier merged 1 commit into
devfrom
feat/utm-external-links
Sep 30, 2026
Merged

Flotapponnier merged 1 commit into
devfrom
feat/utm-external-links

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

What

utm_source=openchainbench on outbound links. 40 across 25 files: provider sites, docs, repos and X profiles, harness sources, venue and market pages, block explorer transactions, our own GitHub and X.

Applied at render time through withUtm(), never stored. The registry and the specs keep clean URLs, so the JSON the API serves, the citations, the structured data and anything a reader copies stay canonical. Only the href a human clicks is tagged.

Deliberately left clean

Why
non-http(s) mailto:, tel:, #anchors, relative paths, and the cursor:// / vscode: MCP deeplinks on /mcp
our own site, subdomains included tagging an internal link starts a new campaign mid-visit and corrupts session attribution in PostHog
URLs that already carry utm_source a hand-written campaign link keeps its own attribution
identifiers that happen to be URLs the Zenodo DOI and the Creative Commons deed are cited verbatim and appear in JSON-LD as well as in prose
RPC endpoint URLs printed so a reader can paste them into a config; a utm_source in one gets copied into production
machine-readable surfaces /api/*, llms.txt, the sitemap and the JSON-LD builders hand URLs to agents and to other people's pages

"don't miss one"

A missed link renders perfectly and simply reports nothing, so sampling behaviour proves nothing. The test greps the source instead and fails on any literal or template-literal external href that is not wrapped. That is what produced the list of 28 the first pass had left, across about, mcp, methodology, partners, press, team, data-api, rpc, speedtest-rpc, trading-apps, prediction-markets, the header, the sidebar and the footer.

It also asserts the inverse for endpoints: the two modules that render RPC URLs must not import withUtm.

Verified

tsc --noEmit clean, 390 tests pass (10 new), pnpm validate 241 specs valid.

Next

Per the request, this goes to dev first and then only this commit is cherry-picked to main — dev carries 14 other commits that are not part of it.

Providers ask how much traffic we send them, and the honest answer was
"look in your referrer report". For anyone arriving through a browser
that strips the referrer, there was no answer at all. Outbound links now
carry utm_source=openchainbench.

Applied at render time, never stored. The registry and the specs keep
clean URLs, so the JSON the API serves, the citations, the structured
data and anything a reader copies stay canonical; only the href a human
clicks is tagged. 40 links across 25 files: provider sites, docs, repos
and X profiles, harness sources, venue and market pages, block explorer
transactions, our own GitHub and X.

Four kinds are deliberately left clean, and withUtm enforces each:

  - anything that is not http(s). mailto:, tel:, #anchors, relative
    paths, and the cursor:// and vscode: MCP deeplinks on /mcp.
  - our own site, subdomains included. Tagging an internal link starts a
    new campaign mid-visit and corrupts session attribution in PostHog.
  - a URL that already carries utm_source, so a hand-written campaign
    link keeps its own attribution.
  - identifiers that happen to be URLs: the Zenodo DOI and the Creative
    Commons deed are cited verbatim and appear in JSON-LD as well as in
    prose, where a tracking parameter is wrong in both places.

RPC endpoint URLs are the case worth stating twice. They are printed so a
reader can paste them into a config, so a utm_source in one would be
copied into production. They never reach the helper, and a test asserts
that the two modules that render them do not import it.

The machine-readable surfaces are excluded too: /api/*, llms.txt, the
sitemap and the JSON-LD builders hand URLs to agents and to other
people's pages, where a tracking parameter ends up inside a citation or
somebody else's HTML.

Missing one of these is invisible: the link works and simply reports
nothing. So the test greps the source rather than sampling behaviour. It
fails on any literal or template-literal external href that is not
wrapped, which is what caught the 28 the first pass had left, and it will
fail on the next one somebody adds.
@Flotapponnier
Flotapponnier merged commit 07c3f8c into dev Sep 30, 2026
2 checks passed
@Flotapponnier
Flotapponnier deleted the feat/utm-external-links branch September 30, 2026 19:39
Flotapponnier added a commit that referenced this pull request Sep 30, 2026
Providers ask how much traffic we send them, and the honest answer was
"look in your referrer report". For anyone arriving through a browser
that strips the referrer, there was no answer at all. Outbound links now
carry utm_source=openchainbench.

Applied at render time, never stored. The registry and the specs keep
clean URLs, so the JSON the API serves, the citations, the structured
data and anything a reader copies stay canonical; only the href a human
clicks is tagged. 40 links across 25 files: provider sites, docs, repos
and X profiles, harness sources, venue and market pages, block explorer
transactions, our own GitHub and X.

Four kinds are deliberately left clean, and withUtm enforces each:

  - anything that is not http(s). mailto:, tel:, #anchors, relative
    paths, and the cursor:// and vscode: MCP deeplinks on /mcp.
  - our own site, subdomains included. Tagging an internal link starts a
    new campaign mid-visit and corrupts session attribution in PostHog.
  - a URL that already carries utm_source, so a hand-written campaign
    link keeps its own attribution.
  - identifiers that happen to be URLs: the Zenodo DOI and the Creative
    Commons deed are cited verbatim and appear in JSON-LD as well as in
    prose, where a tracking parameter is wrong in both places.

RPC endpoint URLs are the case worth stating twice. They are printed so a
reader can paste them into a config, so a utm_source in one would be
copied into production. They never reach the helper, and a test asserts
that the two modules that render them do not import it.

The machine-readable surfaces are excluded too: /api/*, llms.txt, the
sitemap and the JSON-LD builders hand URLs to agents and to other
people's pages, where a tracking parameter ends up inside a citation or
somebody else's HTML.

Missing one of these is invisible: the link works and simply reports
nothing. So the test greps the source rather than sampling behaviour. It
fails on any literal or template-literal external href that is not
wrapped, which is what caught the 28 the first pass had left, and it will
fail on the next one somebody adds.
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.

1 participant