Docs
Everything below is the same API the dashboard uses.
Install the tracker
Create an account at the dashboard, add a site, and paste the tag it gives you.
<script defer src="https://app.stepmetrics.co/t.js" data-site="YOUR_SITE_ID"></script> The site id is public by design. It grants write-only access: it can add events and never read them. Reading requires an API key, which is stored only as a sha256 hash.
Script tag options
| Attribute | Effect |
|---|---|
data-api | Override the collect host. |
data-track-localhost | Record dev traffic. Off by default. |
Custom events
window.stepmetrics('download');
window.stepmetrics('purchase', { plan: 'pro' }, { revenueCents: 2900, currency: 'USD' }); Money is passed in minor units so it stays integral all the way through.
Query the API
GET /v1/sites/:id/overview everything the dashboard needs, in one call
GET /v1/sites/:id/summary totals + named conversion counts
GET /v1/sites/:id/timeseries visitors/pageviews per hour or day
GET /v1/sites/:id/realtime visitors active in the last 5 minutes
GET /v1/sites/:id/pages top pages
GET /v1/sites/:id/sources acquisition sources
GET /v1/sites/:id/breakdown/:dimension country|device|browser|os|medium|campaign|entryPath|exitPath
GET /v1/sites/:id/funnels/:funnelId ordered funnel Segments and ranges
Any read endpoint accepts country, device, browser,
os, source and entryPath, and they compose.
Ranges are period=24h|7d|30d|90d|12mo or an explicit from and
to ISO pair.
An unrecognised period returns a 400 rather than falling back to a default window.
Add includeBots=true to see what the bot filter removed.
Connect an agent over MCP
claude mcp add --transport http analytics https://app.stepmetrics.co/mcp \
--header "Authorization: Bearer dak_..." Ten read-only tools. The key determines which organisation you are querying, so a site id belonging to someone else returns the same "not found" as a site that does not exist.
Report agent runs
npm install @stepmetrics/sdk
npx stepmetrics init --endpoint https://app.stepmetrics.co --site <SITE_ID> The initialiser identifies the framework, inserts the browser tracker, and writes an SDK bootstrap if the project has AI dependencies. If it cannot identify the project it prints the snippet and exits non-zero rather than guessing, because a snippet written somewhere plausible and wrong shows up as missing data weeks later.
Configuration
Tunables live in the database, not in environment variables, so they change per site or per organisation at runtime with no redeploy.
| Key | Default | Meaning |
|---|---|---|
retentionDays | 400 | How long raw events are kept. |
saltRetentionDays | 3 | How long salts live, i.e. the re-identification window. |
sessionTimeoutMins | 30 | Inactivity gap that ends a visit. |
monthlyEventQuota | 100,000 | Organisation-wide ceiling on events per month. |
collectCountry | true | Set false to store no geography at all. |
excludePaths | [] | Paths never recorded. |
Going over quota returns a 429 and logs it. Events are rejected loudly rather than dropped on the floor.