How Pure Analytics works
Pure Analytics is a privacy-friendly web analytics service. You add one script tag to your site, and you get real-time traffic, referrer, geography, device, campaign and revenue data in a dashboard and through a REST API.
This page is written to be read by both people and AI agents. Every fact here reflects the running system: the tracking snippet, the API contract, the plan limits and the quota behaviour.
In one paragraph
A small JavaScript file on your pages sends events to https://pure-analytics.com/api/track. A Cloudflare Worker validates each event, filters bots, stores it in PostgreSQL, and counts it against your monthly quota. You read the aggregated numbers either in the dashboard at https://pure-analytics.com/dashboard or through the public API at https://pure-analytics.com/api/v1/analytics with an API key.
Architecture
Four pieces: the script on your pages, the ingest Worker, the database, and the two readers on top of it.
| Layer | What runs there |
|---|---|
| Tracking script | https://pure-analytics.com/tracking/utilities/script.js, loaded with defer on your site |
| Ingest | Cloudflare Worker, POST /api/track |
| Storage | PostgreSQL (Supabase), row-level security per account |
| Dashboard | React single-page app on Cloudflare Pages |
| Public API | Cloudflare Worker, GET /api/v1/analytics |
Aggregation happens in the database. The dashboard and the public API call the same aggregation functions, so a number you read through the API is the number you see in the dashboard.
Install the tracking script
Paste this before the closing </body> tag of every page. Replace the data-ea-website-id value with the tracking ID shown when you add a website in the dashboard.
<!-- PureAnalytics Tracking Code -->
<script
defer
data-ea-website-id="YOUR_TRACKING_ID"
data-ea-domain="example.com"
data-ea-track-accuracy="standard"
src="https://pure-analytics.com/tracking/utilities/script.js">
</script>
<!-- End PureAnalytics Tracking Code -->Script attributes
| Attribute | Required | Meaning |
|---|---|---|
data-ea-website-id | yes | Tracking ID of the website, from the dashboard |
data-ea-domain | no | Your domain, used to tell internal from external links |
data-ea-track-accuracy | no | How much is tracked. See the accuracy levels below. Default accurate |
data-ea-stripe-key | no | Stripe publishable key, enables client-side revenue tracking |
data-ea-options | no | JSON object overriding individual tracking options |
The script does not run on localhost, on 127.0.0.1, on file:// pages or inside an iframe. That is intentional: your development traffic never reaches your production numbers.
Accuracy levels
Each level adds one class of event. More events mean more detail and a faster burn through your monthly quota.
| Level | Events collected |
|---|---|
| Basic | Page views |
| Standard | Page views, external links |
| Enhanced | Page views, external links, form submissions |
| Professional | Page views, external links, forms, clicks |
| Most Accurate | Page views, external links, forms, clicks, page exits |
Most Accurate is the only level that sets a cookie. Every other level is cookieless.
Custom events
Beyond the automatic events, you can record your own through the global object the script installs.
window.pureAnalytics.track("signup_completed", { plan: "pro" });The first argument is the event name, the second is an optional object of metadata. window.easyAnalytics is a backwards-compatible alias for the same object and points at the same instance.
What is collected and what is not
Collected: page URL and title, referrer, UTM parameters, country derived from the request, browser, operating system, device type, screen size, and the timing of the events you enabled.
Not collected: no IP address is stored, no cross-site identifier, no behavioural profile, no fingerprint sold to a third party. IP anonymisation is on by default, and Do Not Track is respected by default.
Because the default configuration stores no personal data and sets no cookie, most sites can run Pure Analytics without a cookie banner. That is a description of what the software does, not legal advice for your jurisdiction.
Bot filtering
Events are dropped before storage when the request looks automated. Three checks run in order on the ingest Worker: known bot signatures in the user agent, a Chrome user agent arriving without Client Hints, and a source network that belongs to a hosting or datacenter provider. The network check is the one that catches headless browser farms, because the network an event arrives from cannot be spoofed by the page.
Traffic from Apple iCloud Private Relay is deliberately allowed through: those are real visitors on iOS.
Public API
Base URL: https://pure-analytics.com/api/v1/analytics
Authenticate with an API key created in the dashboard, sent in the X-API-Key header. A key is scoped to one or more of your websites; asking for a website the key does not cover returns 403.
Query parameters
| Parameter | Default | Meaning |
|---|---|---|
website_id | all websites on the key | Website UUID or tracking ID |
start | 30 days before end | ISO 8601 start of the period |
end | now | ISO 8601 end of the period |
metrics | visitors,pageviews,bounce_rate | Comma-separated list, see below |
groupBy | none | Adds a breakdown by one dimension |
limit | 10 | Rows returned in the breakdown |
granularity | day | Bucket size of the timeseries: hour, day, week, month |
Metrics
visitors, sessions, pageviews, unique_pageviews, bounce_rate, engagement_rate, avg_session_seconds, views_per_session, plus two that return their own array: timeseries and revenue.
avg_session_duration and avg_session_time are accepted as aliases of avg_session_seconds.
Breakdown dimensions
Valid values for groupBy: page, entry_page, exit_page, country, browser, device, os, referrer, channel, source, medium, campaign.
Every breakdown row reports visitors, sessions and pageviews separately, so there is never an ambiguous single count.
Example request
curl -s "https://pure-analytics.com/api/v1/analytics?metrics=visitors,pageviews,bounce_rate&groupBy=country&limit=5" \
-H "X-API-Key: YOUR_API_KEY"Example response
{
"website_ids": ["8f3ca1d2-....-...."],
"period": {
"start": "2026-08-02T00:00:00.000Z",
"end": "2026-09-01T00:00:00.000Z",
"timezone": "Europe/Rome"
},
"visitors": 4821,
"pageviews": 11204,
"bounce_rate": 42.7,
"breakdown": [
{ "country": "IT", "visitors": 1902, "sessions": 2210, "pageviews": 5104 }
]
}The reporting timezone is the one configured on the website. When a single call spans several websites the response is in UTC, because mixing timezones in one bucket would produce a series that matches none of the sites.
Revenue
Ask for metrics=revenue and the response carries one row per currency with gross, refunded, net, transactions and refunds. Amounts in different currencies are never summed together.
Errors
| Status | Cause |
|---|---|
401 | Missing, unknown, inactive or expired API key |
403 | The requested website is not associated with the key |
400 | No website on the key, or an unsupported groupBy value |
429 | The anti-abuse ceiling for the account has been reached |
Plans and limits
Limits are events per month, counted across all your websites.
| Plan | Events per month | Price |
|---|---|---|
| Free | 1,000 | €0 |
| Starter | 5,000 | €19 |
| Pro | 25,000 | €49 |
| Enterprise | 75,000 | €89 |
| Scale | 150,000 | €149 |
| Unlimited | 300,000 | €249 |
What happens when you go over
Going over your plan limit does not drop your events. You are notified once per month inside the app, and collection continues. Losing a customer's data to enforce a price tier is not a trade we make.
A separate ceiling, ten times the plan limit, exists to protect the infrastructure against abuse. Past that point the ingest returns 429. If the quota counter itself fails, tracking proceeds anyway: a quota problem must never break collection.
An account whose payment is late keeps its plan limit during the grace period. An account with no active subscription falls back to the Free limit of 1,000 events.
Machine-readable resources
These URLs exist so an agent can read the product without rendering a page.
| Resource | URL |
|---|---|
| Short summary for language models | https://pure-analytics.com/llms.txt |
| This page, full text | https://pure-analytics.com/llms-full.txt |
| This page, Markdown | https://pure-analytics.com/docs.md |
| Sitemap | https://pure-analytics.com/sitemap.xml |
| Tracking script | https://pure-analytics.com/tracking/utilities/script.js |
Every public page of this site is served as complete server-rendered HTML, so a crawler that does not execute JavaScript still reads the content.
Where to go next
The rest of the site, for a human reader.
- Comparisons:
/compare/google-analytics,/compare/plausible,/compare/fathom,/compare/simple-analytics - Blog:
/blog - Privacy policy:
/privacy - Sign up or sign in:
/login