Skip to content

Server-side events

Send pageviews and goals from your backend, a proxy or a log file, so traffic the browser script never sees still counts.

The tracking script covers the browser. Some traffic never runs it: visitors with blockers, API clients, crawlers, and things that happen on your server. The events endpoint takes those from wherever they happen and pushes them through the same pipeline, so they land in the same charts under the same rules.

Send events

POST /sites/:site/events takes up to 500 events per request and needs owner or editor. Each event is a pageview or a goal.

bash
curl -X POST -H "Authorization: Bearer sta_your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "type": "pageview", "url": "https://yourstartup.com/pricing", "ip": "203.0.113.9",
        "ua": "Mozilla/5.0 ...", "referrer": "https://news.ycombinator.com/" },
      { "type": "goal", "name": "trial_started", "url": "https://yourstartup.com/app",
        "visitor": "0123456789abcdef01234567", "props": { "plan": "pro" } }
    ]
  }' \
  "https://statsy.co/api/v1/sites/ws_yoursitekey/events"
FieldRequiredNotes
typeYespageview or goal.
urlYesThe full page URL. It must be on your site's domain or one of its extra domains, like a beacon.
nameGoalsThe goal name.
ipNoThe visitor's address, for country and city. Never stored.
uaNoThe visitor's user agent, for device and browser. A crawler user agent goes to the bots report instead.
referrerNoSets the channel and referrer for a new session.
visitorNoThe statsy_vid cookie value. With it the event joins that visitor’s journey and can be credited revenue.
sessionNoA session id to group with, when you have one.
propsNoUp to a few string, number or boolean properties.
tsNoUnix milliseconds. Defaults to now; times far from the present are dropped.

The response is 202 with the number accepted. Enrichment runs after the response; events show up in realtime within a second and in reports on the next rollup.

From the command line

bash
statsy events send --type goal --name trial_started --url https://yourstartup.com/app --visitor 0123456789abcdef01234567
statsy events import ./events.ndjson   # one JSON object per line, sent 500 at a time

Counting crawlers from server logs

Crawlers that never run JavaScript, including most AI training bots, only appear in your web server’s log. Ship those lines and they show up in the bots report. With Caddy, write a JSON access log and turn each line into an event:

Caddyfile
yourstartup.com {
  log {
    output file /var/log/caddy/access.json
    format json
  }
  reverse_proxy app:3000
}
bash
jq -c '{type:"pageview", url:("https://yourstartup.com"+.request.uri), ip:.request.remote_ip, ua:.request.headers["User-Agent"][0], referrer:(.request.headers.Referer[0] // ""), ts:((.ts*1000)|floor)}' \
  /var/log/caddy/access.json > events.ndjson
statsy events import events.ndjson

For Nginx, use a log_format with escape=json and the same jq shape. Send only what the script cannot see, or visits would count twice: filtering the log to known crawler user agents is the usual choice.

Tip. Server-side events obey the site’s excluded paths and IPs, Do Not Track never applies (there is no browser), and a paused workspace accepts nothing.

Frequently asked questions

Can Statsy track visits without JavaScript?

Yes. POST /api/v1/sites/:site/events accepts pageviews and goals from any server. Pass the visitor's IP and user agent and they are counted exactly like script traffic, including location, device, channel and bot filtering.

Do server-side events double count visits the script already sent?

They can, if you send both for the same page load. Send server-side events only for pages the script does not cover, or for goals that happen outside the browser, such as a webhook or a cron job.

Last updated · Markdown version