# 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.

Section: CLI, MCP and API  
Canonical page: https://statsy.co/docs/developers/api-events  
Last updated: 2026-09-21

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"
```

| Field | Required | Notes |
| --- | --- | --- |
| `type` | Yes | `pageview` or `goal`. |
| `url` | Yes | The full page URL. It must be on your site's domain or one of its extra domains, like a beacon. |
| `name` | Goals | The goal name. |
| `ip` | No | The visitor's address, for country and city. Never stored. |
| `ua` | No | The visitor's user agent, for device and browser. A crawler user agent goes to the bots report instead. |
| `referrer` | No | Sets the channel and referrer for a new session. |
| `visitor` | No | The `statsy_vid` cookie value. With it the event joins that visitor’s journey and can be credited revenue. |
| `session` | No | A session id to group with, when you have one. |
| `props` | No | Up to a few string, number or boolean properties. |
| `ts` | No | Unix 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:

```text
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.

Previous: [Payment API](https://statsy.co/docs/developers/api-payments)  
Next: [Alerts and share links API](https://statsy.co/docs/developers/api-alerts-and-share)