Pirsch: server-side analytics without cookies, in Go
Pirsch is a drop-in, server-side, no-cookie, and privacy-focused analytics solution for Go.
At a glance
- What is it?
- Pirsch is the open source core of a privacy focused analytics product, and it identifies visitors by hashing their IP address, User-Agent, the date and a salt, so there is no cookie to consent to and no personal data to store. It is written in Go, stores its events in ClickHouse, and the repository is currently sitting on a long run of 7.0.0 release candidates.
- Who is it for?
- Adopt Pirsch if you run a Go service and you want traffic analytics without cookies and without a personal data store, and if you are willing to run ClickHouse alongside it. Do not adopt it if you need per visitor identity across browsers, because a salted hash of an address and a user agent is deliberately a rotating pseudonymous value, and do not adopt it if you want a stable release to depend on, since the visible tags are all 7.0.0 release candidates.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A fingerprint instead of a cookie
The README explains the identification model in a few sentences, and it is the whole design of the library.
Pirsch generates a unique fingerprint for each visitor. The fingerprint is a hash of the visitor's IP address, User-Agent, the date, and a salt. The tracking works without invading the visitor's privacy. It doesn't use cookies and no personal information is stored, making it GDPR, CCPA and PECR compliant. And if used on the server-side, Pirsch can track visitors using ad blockers.
That last sentence is the one that explains the architecture. A client-side analytics script is invisible to a visitor whose browser blocks it, which means the numbers are the numbers of the people who did not block you. A server-side tracker sits on the request path, after the visitor's browser has already decided whether to cooperate, and so it sees the request either way.
The date in the hash is what makes this work as a privacy model rather than as a tracking model. Because the date is part of the input, the fingerprint for a given address and user agent is different tomorrow, so a fingerprint identifies a visit on a given day rather than a person across time. That is a design decision with a direct consequence: the identifiers are pseudonymous and short lived, and the privacy claim depends on it.
The project also says where it comes from. It originally started as an experiment to reliably analyze web traffic from the server-side using Go, and the repository carries a link to that write-up. Pirsch is made in the EU and hosted on German servers at Hetzner, and there is an interactive dashboard demo at pirsch.pirsch.io.
The package path is github.com/pirsch-analytics/pirsch/v7, and the go.mod declares go 1.27.0.
What the storage layer is made of
The dependency list in go.mod describes the architecture of a self-hosted analytics service more precisely than the README does.
The storage engine is ClickHouse, through ClickHouse/clickhouse-go/v2 at 2.49.0. That is the event store, and it is the heaviest dependency in the list, which tells you immediately that running Pirsch means running ClickHouse.
There is a Redis dependency, go-redis/redis/v8, together with go-redsync/redsync/v4, which is a distributed lock library for Redis. A lock in an analytics pipeline is there to serialise work across instances, which is what you need when several of your Go processes are writing to the same store.
Two dependencies point at data enrichment. oschwald/maxminddb-golang is the MaxMind GeoIP database reader, so country and region data come from a MaxMind database rather than being sent to a third party service. And emvi/iso-639-1 is a language code table, which is what you need to turn an Accept-Language header into a language for the reports.
The rest is a small set of ordinary Go dependencies. github.com/dchest/siphash is a keyed hash function, github.com/gocarina/gocsv writes CSV exports, github.com/mattn/go-sqlite3 is a SQLite driver, google/uuid generates identifiers, stretchr/testify is the test framework, and golang.org/x/net is the usual networking package. The indirect list adds brotli and lz4 compression, xxhash, opentelemetry and yaml.
The repository structure matches. There is a pkg/ directory holding the library, a scripts/ directory holding the generators, a test/ directory, a vendor/ directory, and the usual CHANGELOG.md, CONTRIBUTING.md and LICENSE. The presence of vendor/ is the direct result of the build script, which runs go mod vendor as part of the deps target.
One thing that is not in the README at all is worth noting, and it is a useful one to know. The library is called the open source core of Pirsch Analytics, and the README is explicit about the arrangement. It also offers a managed commercial solution with this library at its core.
Running the tests needs a ClickHouse schema named pirschtest
The contributions section contains the single most useful piece of information for anybody who intends to run this code, and it is short.
To run the tests you'll need a ClickHouse database and a schema called pirschtest. The user is set to default with no password.
That is the whole test setup, and it is a real constraint rather than a detail. The test suite is not self contained, so a contributor needs a ClickHouse instance before anything runs. The Makefile shows the invocation:
test:
CGO_ENABLED=1 go test -cover -race -p 1 github.com/pirsch-analytics/pirsch/v7/pkg/...Three flags in that line are worth reading. CGO_ENABLED=1 is set because mattn/go-sqlite3 is a cgo package, so the tests need a C toolchain. The race detector is on. And -p 1 limits the test parallelism to one package at a time, which is a strong hint that the tests are not safe to run concurrently, most likely because they share a ClickHouse schema and clean up between runs.
The dependencies target is a three step script that also explains the vendor directory in the tree.
deps:
go get -u -t ./...
go mod vendor
go mod tidySo the workflow is to pull the test dependencies, vendor them, and tidy the module file. The Makefile also has fix, which runs go fix and go fmt, and a set of generator targets for the data the library ships:
referrer:
go run scripts/update_referrer_list/update_referrer_list.go
referrer_blacklist:
go run scripts/update_referrer_blacklist/update_referrer_blacklist.go
ua:
go run scripts/update_ua_blacklist/update_ua_blacklist.go
browser:
go run scripts/update_browser_blacklist/update_browser_blacklist.goThose four scripts maintain the referrer list, the referrer blacklist, the user agent blacklist and the browser blacklist, which are data assets rather than code, and they are kept in step with the source by running the generator rather than by editing the output.
The AGPL and the pull request ownership condition
Two conditions in the contributions section deserve a careful reading, because together they define what the project is.
The first is the standard one. Contributions are welcome, and you should open a pull request for your changes and tickets if you would like to discuss something or you have a question.
The second is not standard. The README notes that we only accept pull requests if you transfer the ownership of your contribution to us, and gives the reason: as we also offer a managed commercial solution with this library at its core, we want to make sure we can keep control over the source code.
That is a copyright assignment condition on contributions, and it is a common arrangement for a project that has a commercial product built on top of the open source core. The practical consequence is that the community contribution model is narrower than the open source licence alone would suggest. You can use the code under the AGPL, and you can file issues and discuss things, but a pull request means handing over the copyright of that contribution so the vendor keeps control of the tree. For a company that has a policy about contributing to AGPL projects, that is a decision to make before you open the pull request rather than after.
The licence itself is GNU AGPLv3, as the README states, and the metadata agrees. The AGPL is the copyleft variant with the network clause, so if you modify the library and offer it over a network, the source has to be available to those users. For a team that only runs the library internally, the usual reading is that the trigger does not apply to your own users, but that question is one for your own legal review rather than for this article.
The v7 release candidate run
The release history is the part of this repository that needs a caveat, and it is visible in the tags.
The three most recent releases are v7.0.0-rc53 on 2026-10-13, v7.0.0-rc54 on 2026-10-13, and v7.0.0-rc55 on 2026-10-15, and the last push was on 2026-10-15. So the current major line is in its release candidate phase, with candidates appearing several times a week at the moment.
That is normal for a project that is preparing a major release, and the module path carries the v7 suffix, so the versioning is honest about it. What it means for an adopter is that the stable-looking v6 line and the moving v7 line may behave differently, and the CHANGELOG.md in the repository is where the differences are recorded.
There is also a documentation split to be aware of. The product documentation, including the privacy page that the README links, is at docs.pirsch.io, and the code reference is on go.dev for the v7 module path. The README itself is short by design, with the how it works section reduced to the fingerprint explanation and a link to the privacy documentation, so the detail lives outside the repository.
For an evaluation that means the repository is best read as the engine, and the product documentation is where the configuration, the privacy arguments and the operational guidance live.
Editorial conclusion
Adopt Pirsch if you run a Go service and you want traffic analytics without cookies and without a personal data store, and if you are willing to run ClickHouse alongside it. Do not adopt it if you need per visitor identity across browsers, because a salted hash of an address and a user agent is deliberately a rotating pseudonymous value, and do not adopt it if you want a stable release to depend on, since the visible tags are all 7.0.0 release candidates. Verify first that the fingerprint rotation still gives you the session and returning visitor metrics you need, that the ClickHouse schema and the pirschtest database are set up for the test suite, and that the AGPL and the contribution ownership condition fit your plans.
Frequently asked questions
How does Pirsch identify visitors without cookies?
It generates a unique fingerprint for each visitor that is a hash of the visitor's IP address, User-Agent, the date and a salt. Because the date is part of the input, the identifier rotates, no personal information is stored, and the README describes this as making it GDPR, CCPA and PECR compliant.
What does it take to run the Pirsch test suite?
You need a ClickHouse database and a schema called pirschtest, with the user set to default and no password. The Makefile runs the tests with CGO_ENABLED=1 go test -cover -race -p 1 over the pkg/... packages.
Can I run Pirsch without ClickHouse?
The go.mod lists ClickHouse as the first dependency, ClickHouse/clickhouse-go/v2, and the README states that the tests need a ClickHouse database and a schema called pirschtest, so ClickHouse is part of the intended deployment rather than an optional extra.
What are the conditions for contributing to Pirsch?
Contributions are welcome through pull requests, but the README states that pull requests are only accepted if you transfer the ownership of your contribution to the maintainers, because they also offer a managed commercial solution with this library at its core.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pirsch-analytics-pirsch)