Counterscale is a simple web analytics tracker and dashboard that you self-host on Cloudflare.
It's designed to be easy to deploy and maintain, and should cost you near-zero to operate – even at high levels of traffic (Cloudflare's free tier could hypothetically support up to 100k hits/day).
Counterscale is free, open source software made available under the MIT license. See: LICENSE.
Counterscale is powered primarily by Cloudflare Workers and Workers Analytics Engine. As of February 2025, Workers Analytics Engine has maximum 90 days retention, which means Counterscale can only show the last 90 days of recorded data.
- macOS or Linux environment
- Node v20 or above
- An active Cloudflare account (either free or paid)
If you don't have one already, create a Cloudflare account here and verify your email address.
- Go to your Cloudflare dashboard and, if you do not already have one, set up a Cloudflare Workers subdomain
- Enable Cloudflare Analytics Engine beta for your account (screenshot)
- If this is your first time using Workers, you have to create a Worker before you can enable the Analytics Engine. Navigate to Workers & Pages > Overview, click the "Create Worker" button (screenshot) to create a "Hello World" worker (it doesn't matter what you name this Worker as you can delete it later).
- Create a Cloudflare API token. This token needs
Account.Account Analytics
permissions at a minimum (screenshot).- WARNING: Keep this window open or copy your API token somewhere safe (e.g. a password manager), because if you close this window you will not be able to access this API token again and have to start over.
First, sign into Cloudflare and authorize the Cloudflare CLI (Wrangler) using:
npx wrangler login
Afterwards, run the Counterscale installer:
npx @counterscale/cli@latest install
Follow the prompts. You will be asked for the Cloudflare API token you created earlier.
Once the script has finished, the server application should be deployed. Visit https://{subdomain-emitted-during-deploy}.workers.dev
to verify.
NOTE: If this is your first time deploying Counterscale, it may take take a few minutes before the Worker subdomain becomes live.
You can load the tracking code using one of two methods:
When Counterscale is deployed, it makes tracker.js
available at the URL you deployed to:
https://{subdomain-emitted-during-deploy}.workers.dev/tracker.js
To start reporting website traffic from your web property, copy/paste the following snippet into your website HTML:
<script
id="counterscale-script"
data-site-id="your-unique-site-id"
src="https://{subdomain-emitted-during-deploy}.workers.dev/tracker.js"
defer
></script>
The Counterscale tracker is published as an npm module:
npm install @counterscale/tracker
Initialize Counterscale with your site ID and the URL of your deployed reporting endpoint:
import * as Counterscale from "@counterscale/tracker";
Counterscale.init({
siteId: "your-unique-site-id",
reporterUrl: "https://{subdomain-emitted-during-deploy}.workers.dev/collect",
});
If the website is not immediately available (e.g. "Secure Connection Failed"), it could be because Cloudflare has not yet activated your subdomain (yoursubdomain.workers.dev). This process can take a minute; you can check in on the progress by visiting the newly created worker in your Cloudflare dashboard (Workers & Pages → counterscale).
When you initialize the Counterscale tracker, set autoTrackPageviews
to false
. Then, you can manually call Counterscale.trackPageview()
when you want to record a pageview.
import * as Counterscale from "@counterscale/tracker";
Counterscale.init({
siteId: "your-unique-site-id",
reporterUrl: "https://{subdomain-emitted-during-deploy}.workers.dev/collect",
autoTrackPageviews: false, // <- don't forget this
});
// ... when a pageview happens
Counterscale.trackPageview();
The deployment URL can always be changed to go behind a custom domain you own. More here.
See Contributing for information on how to get started.
There is only one "database": the Cloudflare Analytics Engine dataset, which is communicated entirely over HTTP using Cloudflare's API.
Right now there is no local "test" database. This means in local development:
- Writes will no-op (no hits will be recorded)
- Reads will be read from the production Analaytics Engine dataset (local development shows production data)
Cloudflare Analytics Engine uses sampling to make high volume data ingestion/querying affordable at scale (this is similar to most other analytics tools, see Google Analytics on Sampling). You can find out more how sampling works with CF AE here.