Skip to content

feat: name hosted collectors, allow reporting-only beacons - #1

Merged
sanjaydotpro merged 1 commit into
mainfrom
feat/snow-analytics-collector
Sep 6, 2026
Merged

sanjaydotpro merged 1 commit into
mainfrom
feat/snow-analytics-collector

Conversation

@sanjaydotpro

Copy link
Copy Markdown
Contributor

Why

Beacon is a protocol client, but the endpoint default only ever named SnowSEO, so pointing it at any other collector meant spelling out a full URL — and getting that URL subtly wrong (a bare origin, or the wrong mount path) fails as an opaque 401 rather than a 404.

A pure analytics install also carried three options whose only job was to switch off features it never asked for: siteUrl, a resolve: () => null that existed to satisfy a constructor check, and strictNegotiation: false to stop the beacon answering 406 for the site's own JSON endpoints.

After

createBeacon({ analytics: { key: process.env.SNOW_API_KEY!, collector: "snow-analytics" } });

Changes

  • analytics.collector takes a name from the new exported COLLECTORS map ("snow-analytics" | "snowseo") and fills in the ingest URL. endpoint still wins, for self-hosted collectors.
  • Reporting-only beacons. createBeacon({ analytics }) with no dir/resolve is a valid install instead of a thrown error.
  • strictNegotiation defaults to false for reporting-only beacons, stays true when twins are served. Explicit values override both.
  • siteUrl is optional, required only by the methods that mint absolute URLs, which throw an error naming it.
  • host is optional on the wire. A key belongs to one site, so a collector can resolve it. The client omits it only when given neither siteUrl nor analytics.host; beacon-server falls back to the key's host when the key names exactly one, and answers 400 when it names several, where guessing would file hits under the wrong site. A present-but-empty host is still rejected.

Compatibility

Existing installs are unaffected: anything passing siteUrl sends host exactly as before, and the endpoint default is still SnowSEO. Both packages bumped to 0.1.8.

Verification

  • pnpm check, build, type-check, test — 282 tests pass (198 beacon + 84 beacon-server), plus examples:type-check and examples:build, i.e. every gate CI runs.
  • End-to-end against a real Snow Analytics ingest: a beacon built with no siteUrl and no host posted a GPTBot hit and got 200, and the server resolved the site from the key (verified by the crawler-detected milestone landing on the right site).

🤖 Generated with Claude Code

Beacon is a protocol client, but the endpoint default only ever named
SnowSEO, so pointing it at any other collector meant spelling out a full
URL — and getting that URL subtly wrong (a bare origin, or the wrong
mount path) fails as an opaque 401 rather than a 404.

`analytics.collector` now takes a name from the exported COLLECTORS map
("snow-analytics" or "snowseo") and fills the endpoint in. `endpoint`
still wins, for self-hosted collectors.

A pure analytics install also had to carry three options whose only job
was to switch off features it never asked for: `siteUrl`, a
`resolve: () => null` that existed to satisfy a constructor check, and
`strictNegotiation: false` to stop the beacon answering 406 for the
site's own JSON endpoints. All three are gone:

  createBeacon({ analytics: { key, collector: "snow-analytics" } })

- `createBeacon` with `analytics` and no `dir`/`resolve` is now a valid
  reporting-only install instead of a thrown error.
- `strictNegotiation` defaults to false for reporting-only beacons and
  stays true when twins are served. Explicit values override both.
- `siteUrl` is optional, and required only by the methods that mint
  absolute URLs, which throw an error naming it.
- `host` is optional on the wire: a key belongs to one site, so the
  collector resolves it. The client omits it only when given neither
  `siteUrl` nor `analytics.host`; beacon-server falls back to the key's
  host when the key names exactly one, and answers 400 when it names
  several, where guessing would file hits under the wrong site. A
  present-but-empty host is still rejected.

Existing installs are unaffected: anything passing siteUrl sends host
exactly as before, and the endpoint default is still SnowSEO.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sanjaydotpro
sanjaydotpro merged commit 3f67262 into main Sep 6, 2026
2 checks passed
@sanjaydotpro
sanjaydotpro deleted the feat/snow-analytics-collector branch September 6, 2026 09:22
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