Mirror of goatcounter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Martin Tournoij a4511bdaa7
Don't try to load a settings tab if the hash is empty
23 hours ago
.github Add CONTRIBUTING file 4 days ago
acme Update copyright notice: add http:// 2 weeks ago
bin Always pass empty object; use non-minified script 1 month ago
cfg Add -debug flag to more easily set zlog.SetDebug() 1 week ago
cmd Fix intermittent failing test for ./cmd/goatcounter (hopefully) 23 hours ago
cron Don't clear existing titles 3 days ago
db Store page title in hit_stats (#102) 3 days ago
docs Add plausable.io to comparisons 2 weeks ago
handlers Expand login token expiry to 1 hour, add some logging for login failures 1 day ago
pack Don't try to load a settings tab if the hash is empty 23 hours ago
public Don't try to load a settings tab if the hash is empty 23 hours ago
tpl Re-enable keyboard input for Pika 1 day ago
.codecov.yaml Use chi router for HTTP tests 4 months ago
.gitattributes Allow -plan to configure default plan, some homepage updates 1 month ago
.gitignore Add binaries for 1.0 release 4 days ago
.gogo-release Update .gogo-release config to enable cgo builds 2 days ago
.ignore Fix/cleanup minor TODO comments 2 months ago
.travis.yml Re-do the browser stats 2 months ago
LICENSE Link to motivation for choosing the EUPL 2 weeks ago
README.markdown Fix go get command in README >_< 2 days ago
admin.go Don't need to list all refs in admin 1 week ago
blacklist.go Update blacklist 1 month ago
gen.go Implement better DB migrations (#97) 1 week ago
go.mod Fix intermittent failing test for ./cmd/goatcounter (hopefully) 23 hours ago
go.sum Fix intermittent failing test for ./cmd/goatcounter (hopefully) 23 hours ago
hit.go Add "where bot=0" to HitStats.List get total 1 day ago
hit_test.go Don't prefill blank days in hit_stats 2 weeks ago
init.go BrowserStats → Stats 1 week ago
memstore.go Collect page title and domain 1 week ago
memstore_test.go Update copyright notice: add http:// 2 weeks ago
netlify.toml Add CORS to all of Netlify 1 day ago
site.go Allow - in site.code 1 day ago
site_test.go Allow - in site.code 1 day ago
test.go Add updates 2 weeks ago
update.go Add updates 2 weeks ago
user.go Expand login token expiry to 1 hour, add some logging for login failures 1 day ago


Build Status codecov

GoatCounter is a web analytics platform, roughly similar to Google Analytics or Matomo. It aims to give meaningful privacy-friendly web analytics for business purposes, while still staying usable for non-technical users to use on personal websites. The choices that currently exist are between freely hosted but with problematic privacy (e.g. Google Analytics), hosting your own complex software or paying $19/month (e.g. Matomo), or extremely simplistic “vanity statistics”.

There are two ways to run this: as hosted service on goatcounter.com, free for non-commercial use, or run it on your own server.

See docs/rationale.markdown for some more details on the “why?” of this project.

There’s a live demo at https://stats.arp242.net.

Please consider donating if you’re self-hosting GoatCounter so I can pay my rent :-)


  • Privacy-aware; doesn’t track users with unique identifiers and doesn’t need a GDPR consent notice. Also see the privacy policy.

  • Lightweight and fast; adds just 3.5K (1.9K compressed) of extra data to your site.

  • Easy; if you’ve been confused by the myriad of options and flexibility of Google Analytics and Matomo that you don’t need then GoatCounter will be a breath of fresh air.

  • Accessibility is a high-priority feature, and the interface works well with screen readers, no JavaScript, and even text browsers (although not all features work equally well without JS).

  • 100% committed to open source; you can see exactly what the code does and make improvements.

  • Own your data; you can always export all data and cancel at any time.


  • Fast: can handle about 800 hits/second on a $5/month Linode VPS using the default settings.

  • Self-contained binary: everything – including static assets – is in a single ~7M statically compiled binary. The only other thing you need is a SQLite database file or PostgreSQL connection (no way around that).

Running your own

There are binaries on the releases page, or compile from source with go get zgo.at/goatcounter/cmd/goatcounter, which will put the binary at ~/go/bin/goatcounter.

Go 1.12 and newer are supported (it follows the Go release policy). You will need a C compiler (for SQLite) or PostgreSQL.


  1. For a production environment run something like:


       -prod \
       -smtp         'smtp://localhost:25' \
       -plan         'pro' \
       -domain       'example.com' \
       -domainstatic 'static.example.com' \
       -emailerrors  'me@example.com' \

The default is to use a SQLite database at ./db/goatcounter.sqlite3 (will be created if it doesn’t exist). See the -dbconnect flag to customize this.

The -prod flag affects various minor things; without it it’ll try to load templates from the filesystem (instead of using the built-in ones), for example.

-smtp is required to send login emails. You can use something like Mailtrap if you just want it for yourself, but you can also use your Gmail or whatnot.

  1. Use a proxy for https (e.g. hitch or caddy); you’ll need to forward example.com and *.example.com

You can see the goathost repo for the server configuration of goatcounter.com, although that is just one way of running it.


You may need to run run database migrations when updating. Use goatcounter -migrate auto to always run all pending migrations on startup. This is the easiest way, although arguably not the “best” way.

Use goatcounter -migrate <file> or goatcounter -migrate all to manually run migrations; generally you want to upload the new version, run migrations while the old one is still running, and then restart so the new version takes effect.


Both SQLite and PostgreSQL are supported. SQLite should work well for the vast majority of people and is the recommended database engine. PostgreSQL will not be faster in most cases, and the chief reason for adding support in the first place is to support load balancing web requests over multiple servers. To use it:

  1. Create the database, unlike SQLite it’s not done automatically:

    $ createdb goatcounter $ psql goatcounter -c ‘\i db/schema.pgsql’

  2. Run with -pgsql and -dbconnect, for example:

    $ goatcounter -pgsql -dbconnect ‘user=goatcounter dbname=goatcounter sslmode=disable’

See the pq docs for more details on the connection string.

  1. You can compile goatcounter without cgo if you don’t use SQLite:

    $ CGO_ENABLED=0 go build

Functionally it doesn’t matter too much, but you won’t need a C compiler, builds will be faster, and makes creating static binaries easier.


See .github/CONTRIBUTING.markdown for details on how to run a development server, write patches, etc.