GoatCounter is an open source web analytics platform available as a hosted service or self-hosted app

Awesome Humane Tech

GoatCounter is an open source web analytics platform available as a hosted service (free for non-commercial use) or self-hosted app. It aims to offer easy to use and meaningful privacy-friendly web analytics as an alternative to Google Analytics or Matomo.

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. The source code is completely Open Source/Free Software, and it can be self-hosted without restrictions.

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 contributing financially if you're self-hosting GoatCounter so I can pay my rent :-) GoatCounter is sponsored by a grant from NLnet's NGI Zero PET fund.

Features

  • Privacy-aware; doesn’t track users with unique identifiers and doesn't need a GDPR notice. Fine-grained control over which data is collected. Also see the privacy policy and GDPR consent notices.

  • Lightweight and fast; adds just ~3.5K of extra data to your site. Also has JavaScript-free "tracking pixel" option, or you can use it from your application's middleware or import from logfiles.

  • Identify unique visits without cookies using a non-identifiable hash (technical details).

  • Keeps useful statistics such as browser information, location, and screen size. Keep track of referring sites and campaigns.

  • 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 assistive technology such as screen readers.

  • 100% committed to open source; you can see exactly what the code does and make improvements, or self-host it for any purpose.

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

  • Integrate on your site with just a single script tag:

    ">
    
    
  • The JavaScript integration is a good option for most, but you can also use a no-JavaScript image-based tracker, integrate it in your backend middleware, or parse log files.

Getting data in to GoatCounter

There are three ways:

  1. Add the JavaScript code on your site; this is the easiest and most common method. Detailed documentation for this is available at https://www.goatcounter.com/code

  2. Integrate in your middleware; send data to GoatCounter by calling the API from your backend server middleware. Detailed documentation for this is available at https://www.goatcounter.com/api#backend-integration

  3. Parse logfiles. GoatCounter can parse logfiles from nginx, Apache, CloudFront, or any other HTTP middleware or proxy. See goatcounter help import for detailed documentation on this.

Running your own

The release page has binaries for Linux amd64, arm, and arm64. These are statically compiled, contain everything you need, and should work in pretty much any Linux environment. The only other thing you need is somewhere to store a SQLite database file or a PostgreSQL connection.

GoatCounter should run on any platform supported by Go, but there are no binaries for them (yet); you'll have to build from source if you want to run it on e.g. FreeBSD or macOS.

Note this README is for the latest master; use the release-2.0 branch for the 2.0 README.

Generally speaking only the latest release is supported, although critical fixes (security, data loss, etc.) may get backported to previous releases.

Deploy scripts and such

Building from source

You need Go 1.16 or newer and a C compiler (for SQLite). If you compile it with CGO_ENABLED=0 you don't need a C compiler but can only use PostgreSQL.

Compile from source with:

$ git clone -b release-2.0 https://github.com/zgoat/goatcounter.git
$ cd goatcounter
$ go build -ldflags="-X zgo.at/goatcounter.Version=$(git log -n1 --format='%h_%cI')" ./cmd/goatcounter

You'll now have a goatcounter binary in the current directory.

The -ldflags=[..] sets the version; this isn't strictly required as such, but it's recommended as it's used to "bust" the cache for static files and may also be useful later when reporting bugs. This can be any string and doesn't follow any particular format, you can also set this to the current date or banana or anything you want really.

To build a fully statically linked binary:

$ go build -tags osusergo,netgo,sqlite_omit_load_extension \
    -ldflags="-X zgo.at/goatcounter.Version=$(git log -n1 --format='%h_%cI') -extldflags=-static" \
    ./cmd/goatcounter

It's recommended to use the latest release as in the above command. The master branch should be reasonably stable but no guarantees, and sometimes I don't write detailed release/upgrade notes until the actual release so you may run in to surprises.

You can compile goatcounter without cgo if you're planning to use PostgreSQL and don't use SQLite:

$ CGO_ENABLED=0 go build \
    -ldflags="-X zgo.at/goatcounter.Version=$(git log -n1 --format='%h_%cI')" \
    ./cmd/goatcounter

Functionally it doesn't matter too much, but builds will be a bit easier and faster as it won't require a C compiler.

Running

You can start a server with:

$ goatcounter serve

The default is to use an SQLite database at ./db/goatcounter.sqlite3, which will be created if it doesn't exist yet. See the -db flag and goatcounter help db to customize this.

Both SQLite and PostgreSQL are supported. SQLite should work well for most smaller sites, but PostgreSQL gives better performance. There are some benchmarks over here to give some indication of what performance to expect from SQLite and PostgreSQL.

GoatCounter will listen on port *:80 and *:443 by default. You don't need to run it as root and can grant the appropriate permissions on Linux with:

$ setcap 'cap_net_bind_service=+ep' goatcounter

Listening on a different port can be a bit tricky due to the ACME/Let's Encrypt certificate generation; goatcounter help listen documents this in depth.

You can create new sites with the db create site command:

$ goatcounter db create site -vhost stats.example.com -user.email [email protected]

This will ask for a password for your new account; you can also add a password on the commandline with -password. You must also pass the -db flag here if you use something other than the default.

Updating

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

Use goatcounter migrate 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.

Use goatcounter migrate pending to get a list of pending migrations, or goatcounter migrate list to show all migrations.

PostgreSQL

To use PostgreSQL run GoatCounter with a custom -db flag; for example:

$ goatcounter serve -db 'postgresql://dbname=goatcounter'
$ goatcounter serve -db 'postgresql://host=/run/postgresql dbname=goatcounter sslmode=disable'

This follows the format in the psql CLI; you can also use the PG* environment variables:

$ PGDATABASE=goatcounter DBHOST=/run/postgresql goatcounter serve -db 'postgresql://'

See goatcounter help db and the pq docs for more details.

Development/testing

You can start a test/development server with:

$ goatcounter serve -dev

The -dev flag makes some small things a bit more convenient for development; TLS is disabled by default, it will listen on localhost:8081, the application will automatically restart on recompiles, templates and static files will be read directly from the filesystem, and a few other minor changes.

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

Various aggregate data files are available at https://www.goatcounter.com/data

Comments
  • How do you run this through a proxy?

    How do you run this through a proxy?

    I'm not really familiar with Go, but I've run go build -ldflags="-X main.version=$(git log -n1 --format='%h_%cI')" ./cmd/goatcounter and it was able to download the files.

    It seems the next step is to run goatcounter serve but that just returns a goatcounter not found

  • Reports over 1 month are empty

    Reports over 1 month are empty

    Hello,

    Using the Team Kodi account, I cannot seem to generate a report greater than 1 month. When I attempt to generate a report for 3 months I end up with one of the following screens.

    Is this a known issue?

    goat1

    goat2

  • Add/expand self-hosting guide

    Add/expand self-hosting guide

    I think a step-by-step guide with examples for setting up goatcounter on a fresh VPS to a production-ready state could go a long way with making self-hosting more approachable. I've just finished setting it up myself and here are a few particular issues I encountered:

    1. time.LoadLocation(...) which is used by your tz module (used in goatcounter) expects that system has a list of all timezones available, and fails with a quite cryptic error message when it cannot find it: panic: tz.init: unknown time zone Asia/Kabul (or some other random timezone). This requires something like apk add tzdata or apt install tzdata (depending on distro) to fix.

    2. When calling goatcounter create, it's not intuitive for a first-time user that -domain is the domain where goatcounter runs, not the tracked domain. Also, I'm still not sure what the -parent parameter does, and the -h description doesn't really help. Also, I think -createdb should be the default, as otherwise it just panics saying it couldn't find the database file. serve creates the DB automatically, I don't see a reason why create shouldn't.

    3. Adding some basic instructions on how to setup goatcounter to run automatically using systemd would be nice for first timers, although I understand that it's out of scope for goatcounter. :)

    Few articles I found around the internet, which may serve as an inspiration:

    • https://rgth.co/blog/replacing-google-analytics-with-goatcounter/
    • https://daulton.ca/2021/01/openbsd-goatcounter-server/

    Lastly, I wanna say thanks for goatcounter - I love both the philosophy and UI. If it proves to work well over time, I'll gladly send some donations your way. :)

  • i18n support

    i18n support

    Hey Martin,

    I really love what you did here. It's a really nice tool. I'm using the goatcounter the first time and for my customer I need to translate it in german, because english is not "allowed". Are you planning on internationalization/multi-language support any soon? Or is my only option currently to translate all files. I was also thinking about creating a pull request with some i18n-package.

    Thank you already, Marco

  • Show State/Province Locations

    Show State/Province Locations

    I stumbled upon GoatCounter yesterday and am very impressed. (So long Matomo.) The only missing information I noticed is location by state/province. In Canada, USA, China etc, I think it's useful to be able to see what state people are visiting from.

  • Docker

    Docker

    I would love to make a pull request but I'm really not quiet strong with the Dockerness. I think having a Dockerfile, docker-compose.yml, and an official docker image might make it easier for certain people to use and work on goatcounter.

  • Is there any way to _populate_ an existing, empty, PostgreSQL database without manually pulling the schema from `goatcounter db schema-pgsql`?

    Is there any way to _populate_ an existing, empty, PostgreSQL database without manually pulling the schema from `goatcounter db schema-pgsql`?

    Is there any way to populate an existing, empty, PostgreSQL database without manually pulling the schema from goatcounter db schema-pgsql?

    Running goatcounter db create site complains about migrations that haven't been run, but running goatcounter db migrate fails with:

    goatcounter: zdb.Migrate.Run: running "2020-08-28-1-paths-tables": pq: relation "hits" does not exist
    

    Originally posted by @jbg in https://github.com/zgoat/goatcounter/issues/452#issuecomment-829985048

  • Site switcher in top-left corner looks squished/weird once you have a lot of sites

    Site switcher in top-left corner looks squished/weird once you have a lot of sites

    Is there a way to apply our own custom CSS to the dashboard?

    https://rgth.co/blog/replacing-google-analytics-with-goatcounter/

    I followed the tutorial above, where are the files located for the doing so?

    Thanks

  • [HELP] -stripe: must be set.

    [HELP] -stripe: must be set.

    Creating goatcounter binary from the newest source codes, and trying to starte it, then goatcounter print help messages and doesn't start.

    Does -stripe flag become essential? If so, how is necessary keys created? What parameters should I assign in Stripe? Could you tell me step-by-step procedure?

  • Deal with adblockers etc. better

    Deal with adblockers etc. better

    GoatCounter got added to EasyList Privacy as follows:

    ||gc.zgo.at^$third-party
    ||goatcounter.com/count^$third-party
    

    That was bound to happen sooner or later, and I guess it's not a bad sign that GoatCounter is deemed worthy of inclusion 😅 Because of the third-party option it only gets blocked if it's loaded as 3rd-party script, so goatcounter.com and such still work fine.

    However, I've had some people report that AdGuard simply blocks all of the goatcounter.com domains; the reason for this is that their DNS filter simply includes:

    ||gc.zgo.at^
    ||goatcounter.com^
    

    That's ... a rather crude approach, but it is what it is.

    It would perhaps be better if a different domain was used for the tracking; I already have goatanalytics.com so that's kind of an obvious choice. That way ad blockers can block that, and keep goatcounter.com unblocked.

  • My stats seem to be one month in the future

    My stats seem to be one month in the future

    Hi! I am not sure if I am mistaking something, but it appears that my stats are being dated one month ahead of now --- it is november now, but these stats are claiming to be from december. Any ideas?

    Screen Shot 2021-11-30 at 11 15 20 AM
  • Possibly a new way to do privacy preserving session tracking - address split session tracking

    Possibly a new way to do privacy preserving session tracking - address split session tracking

    https://notes.normally.com/cookieless-unique-visitor-counts/

    outlines a new way to do privacy session tracking. It preserves sessions across IP address changes. It seems similar to the simpleweb anlaytics, I am not sure if it has a similar downside as it gets updated for each request, not just once per day.

    I think this is an issue for me as I have a number of sessions that change session id's but seem to be the same session. I am connecting the sessions since the last page viewed in the prior session is the referer for the page in the new session.

    From what I can tell this is the only thing that can cause a change in the session computation for the same browser as it occurs within a 1 hour time window so salt changeover shouldn't be breaking the session chain.

  • Cross compile with or without CGO

    Cross compile with or without CGO

    Pocketbase can be cross compiled with or without CGO. This is because it imports modernc SQLite.

    I just wanted to point this out as I saw in the readme that this is blocking the project easily producing releases that work in all OS / ARCH.

    the non cgo SQLite IS Slower. About 30%. It may however get better and better as modernc is in constant updates .

  • Facets

    Facets

    I did not look at the underlying aggregation logic , but this thing would be awesome if it also had facets .

    So you can do cross referencing of a specific page against location of visitors , etc etc

    i expect the vision is to keep this out of the feature set ? YAGNI o guess for most people ?

  • API for page views for a page

    API for page views for a page

    From what I can tell, I can get page views as a whole, /api/v0/stats/hits, but I can't get it for a page. There is an API for referrals for a page, but not page views.

    Related - the API for referrals for a page mentions you have to pass a page ID, but what if you don't know the ID, just the path? Can we support passing a path and getting info that way?

  • Proxied usage: Admin/Dashboard: Chrome problem

    Proxied usage: Admin/Dashboard: Chrome problem

    Thanks for a great tool! I`m using it with nginx by proxing access and this works well except admin area, details below.

    Basically it works in FireFox, but not working in Chrome. Subdomain for goat Dashboard is served under http (don`t need another certificate). But any login attempt just show login page again. I believe this is because in chrome login cookie is blocked, see screenshot:

    Screenshot 2022-12-07 at 11 40 43

    Details:

    • goatcounter started with this commandline params goatcounter serve -automigrate -db sqlite3+/<my_path>/goatcounter.sqlite3 -listen localhost:5000 -tls http latest release from release download was used for install

    • proxied admin access setup (nginx.conf) for subdomain

    	server {
    		listen       80;
    		server_name  goat.<my_domain.com>;
    		root         /;
    
    		location / {
    				proxy_set_header Host $http_host;
    				proxy_set_header X-Forwarded-For $remote_addr;
    				proxy_set_header X-Forwarded-Proto $scheme;
    				proxy_set_header X-Real-IP $remote_addr;
    				#proxy_set_header Connection "";
    				#proxy_http_version 1.1;
    				#proxy_redirect off;
    				proxy_pass http://127.0.0.1:5000;
    		}
    	}
    
    • proxied counter access setup (nginx.conf)
    location ~ /goatcounter
    {
    	# headers etc for parsing - https://github.com/arp242/goatcounter/blob/306a482eb28c9603f3c7fba684a3326432637a31/handlers/count.go
    	proxy_set_header Host "goat.gamerotor.com";
    	proxy_set_header X-Forwarded-For $remote_addr;
    	proxy_set_header X-Forwarded-Proto $scheme;
    	proxy_set_header X-Real-IP $remote_addr;
    	proxy_pass http://127.0.0.1:5000/count$is_args$args;
    }
    
  • Added an automatic Docker Container Deployment

    Added an automatic Docker Container Deployment

    An official Docker container would be awesome. It simplifies the deployment a lot and opens the ability to deploy GoatCounter easily on services like Kubernetes. #643

    You just need to add a secret for your Docker-Hub password / token and your username. The Docker container gets automatically build and pushed to the repository.

    Special thanks to @baethon who originally created the Docker file.

Minimalist open-source web analytics

Zero-effort web analytics. This is a self-hosted open-source version of Nullitics.

Nov 10, 2022
Focalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.
Focalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.

Focalboard Like what you see? ?? Give us a GitHub Star! ⭐ Focalboard is an open source, self-hosted alternative to Trello, Notion, and Asana. It helps

Jan 9, 2023
GoTrue is a small open-source API written in Golang, that can act as a self-standing API service for handling user registration and authentication for Jamstack projects.
GoTrue is a small open-source API written in Golang, that can act as a self-standing API service for handling user registration and authentication for Jamstack projects.

GoTrue is a small open-source API written in Golang, that can act as a self-standing API service for handling user registration and authentication for Jamstack projects.

Dec 13, 2021
listmonk is a standalone high performance, self-hosted newsletter and mailing list manager with a modern dashboard. Single binary app.
listmonk is a standalone high performance, self-hosted newsletter and mailing list manager with a modern dashboard. Single binary app.

listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. It uses a PostgreSQL database as its data store.

Jan 1, 2023
longurl is a self-hosted short url service.

longurl Introduction longurl is a self-hosted short url service. Try It Out curl -H "Content-Type:application/json" -X POST --data '{"url": "https://g

Oct 24, 2022
🖖🏻 A self-hosted Quora like web application written in Go
🖖🏻 A self-hosted Quora like web application written in Go

Guora ???? A self-hosted Quora like web application written in Go 基于 Golang 类似知乎的私有部署问答应用 包含问答、评论、点赞、管理后台等功能 Quick Start (Docker Deploy) $ docker-comp

Dec 27, 2022
記帳-PWA-web-app (Bookkeeping-PWA-web-app)
記帳-PWA-web-app (Bookkeeping-PWA-web-app)

GoKeep (bookkeeping web app) 記帳-PWA-web-app (Bookkeeping-PWA-web-app) demo link : https://bookkepping.herokuapp.com/ 測試用帳密 : tester002 , tester002 (亦可

Jan 31, 2022
Remark42 is a self-hosted, lightweight, and simple comment engine
Remark42 is a self-hosted, lightweight, and simple comment engine

Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engine, which doesn't spy on users. It can be embedded into blogs, articles or any other place where readers add comments.

Dec 28, 2022
Mouthful is a self-hosted alternative to Disqus.

Mouthful is a lightweight commenting server written in GO and Preact. It's a self hosted alternative

Dec 20, 2022
Hammond is a self hosted vehicle management system to track fuel and other expenses related to all of your vehicles.
Hammond is a self hosted vehicle management system to track fuel and other expenses related to all of your vehicles.

Hammond is a self hosted vehicle management system to track fuel and other expenses related to all of your vehicles. It supports multiple users sharing multiple vehicles. It is the logical successor to Clarkson which has not been updated for quite some time now.

Jan 2, 2023
Self-hosted video-hosting website and video archival manager for Niconico, Bilibili, and Youtube
Self-hosted video-hosting website and video archival manager for Niconico, Bilibili, and Youtube

Self-hosted video-hosting website and video archival manager for Niconico, Bilibili, and Youtube

Jan 1, 2023
listmonk is a standalone, self-hosted, newsletter and mailing list manager
listmonk is a standalone, self-hosted, newsletter and mailing list manager

listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. It uses a Postg

Aug 15, 2022
A self-hosted golang application that listens for Terraform pull request events via webhooks.
A self-hosted golang application that listens for Terraform pull request events via webhooks.

Atlantis Terraform Pull Request Automation Resources What is Atlantis? What does it do? Why should you use it? Stargazers over time Resources How to g

Dec 9, 2021
Mattermost is an open source platform for secure collaboration across the entire software development lifecycle.
Mattermost is an open source platform for secure collaboration across the entire software development lifecycle.

Mattermost is an open source platform for secure collaboration across the entire software development lifecycle. This repo is the primary source for c

Jan 2, 2023
A simple and privacy focused analytics tool written in go.
A simple and privacy focused analytics tool written in go.

Analytics Box Hello guys, this is privacy friendly analytics tool, Analytics Box for web written in go. It ensures user privacy but at the same time a

Nov 27, 2022
📈 Reincarnation of mrratality - MRR analytics system for SaaS-apps

remrratality Перерождение проекта mrratality с улучшенной архитектурой и стеком. Данный проект будет использован для лабораторных работ по курсам "Тес

Sep 25, 2022
Go-web-scaffold - A simple scaffold for building web app quickly

Go-web-scaffold A simple scaffold for building web app quickly. features This sc

Jan 21, 2022
A job queue and scheduler written in Go, backed by Postgres, and available over HTTP
A job queue and scheduler written in Go, backed by Postgres, and available over HTTP

Rickover This holds the code for a scheduler and a job queue written in Go and backed by Postgres. The goals/features of this project are: Visibility

Dec 31, 2022
log4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web servicelog4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web service
log4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web servicelog4jScanner: provides you with the ability to scan internal (only) subnets for vulnerable log4j web service

log4jScanner Goals This tool provides you with the ability to scan internal (only) subnets for vulnerable log4j web services. It will attempt to send

Jan 5, 2023