Skip to main content
The client that installs on your site and the server that receives from it are both open source, MIT-licensed. Nothing about beacon requires a SnowSEO account. Point the endpoint at a server you control and the hits go there instead. Same client, same wire format, same classification.

Why the split exists

Beacon is two halves, and it matters which half does what. The client reports raw facts: the path, the User-Agent as received, the source address, whether Markdown was negotiated, any signature headers. It deliberately draws no conclusions. The server decides what those facts mean: which crawler this is, and whether it is who it claims to be. That split is not an implementation detail. A client that graded its own traffic would only be repeating what the crawler told it, and a crawler registry compiled into your site’s dependencies goes stale the day after you install it.
This is why there is a server to self-host at all. If classification happened on your site, “self-hosting” would just mean not sending the data anywhere.

What you get, and what you do not

You get

Ingest, crawler classification, IP-range and reverse-DNS verification, Web Bot Auth signature checking, daily rollups, and storage in SQLite or Postgres.

You do not get

A dashboard, a stats API, charts, alerting, crawl-to-referral attribution, or history beyond what your own database holds.
The reference server has exactly two routes: POST /v3/beacon/hits and GET /health. It records classified, verified hits into a database. What you do with them is yours. If you want the dashboard, the maintained verified-crawler dataset and attribution, that is what hosted SnowSEO is. Both run the same ingestBatch function, so the open half cannot quietly drift from the hosted one.

Three ways to do it

1

Run the reference server

One command, or a container. Storage in SQLite by default, Postgres if you want it. See Running the server.
2

Embed the pipeline in an app you already have

@snowseo/beacon-server exports ingestBatch on its own. Call it from your existing Fastify, Express or Hono app and persist however you like. Implement the HitStore interface for your own database.
3

Write your own collector

The wire protocol is frozen and documented, so a collector in Go, Rust or Python is a supported path rather than a hack. You give up the classification engine, which is the hard part.

Requirements

Node 24, or Node 22.5+ with --experimental-sqlite. The SQLite store uses Node’s built-in driver, so there is no native module to compile and no dependency to install. Postgres needs pg, declared as an optional peer dependency and imported only if you choose that store.
The reference server has no rate limiting and no TLS. It is meant to sit behind a reverse proxy. Exposing it directly to the internet is not a configuration we support.