fivebar

Server events

Copy page
View Markdown
Open with
Connect MCP
Cursor VS Code

A service with no pages, such as an API or an MCP server, has nowhere to put the tag. Its own server can send fivebar an event for each call instead.

It takes an API token made to send events, and a request to fivebar for each call, sent once your service has answered, so it never waits on fivebar. Each call counts as a pageview of its route or tool, or as a custom event, on the site’s dashboard, beside any pages its tag counts. A call is never taken for a bot’s, as your token vouches for it.

Make a token

In Settings, under API tokens, make a token for one site, under Only the ones you choose, with Send events ticked and Read stats unticked. A token that only sends reads nothing, so one that leaks from your service shows nobody your stats. Give it to your service in its environment, as FIVEBAR_TOKEN, never in its code.

The site can be your site, its calls counted beside its pages, or a site of its own, such as api.example.com, to keep them apart: add it on Sites first.

A token sends for a site only while you own it or are its editor. It stops within a minute of being revoked, or of you leaving the site, being removed or being made a viewer: see Sharing a site. A token you’ve just made can send from a minute later.

Send an event

For each call, send a POST to https://fiveb.ar/api/events, with the token in the Authorization header, as Bearer and the token, and the event as a JSON object of up to 64 KiB. A basic event, its caller told apart by address and user agent, as a browser is:

{
  "site": "example.com",
  "name": "/v1/postcodes/:code",
  "ip": "203.0.113.7",
  "user_agent": "curl/8.7.1"
}

An advanced one: your service’s account 4821, calling through Claude, with two properties of the call:

{
  "site": "example.com",
  "name": "/v1/postcodes/:code",
  "props": { "status": 200, "format": "json" },
  "ip": "203.0.113.7",
  "id": "4821",
  "client": "claude"
}
FieldHolds
siteRequired. The site’s domain, as the tag’s data-domain names it.
nameRequired. The route or tool called, as your code names it, such as /v1/postcodes/:code rather than the address called, or get_overview. Spaces at its ends are trimmed, anything from a ? or # is cut off, a name without a / first is given one, so get_overview is /get_overview, and it’s cut to 2,048 characters, as a page’s path is.
eventOptional. A custom event’s name, to count the call as that event, on the page name gives, rather than as a pageview. It carries no data: send props instead.
propsOptional. Custom properties for this call, as an object of names and values, such as {"status": 200}, read by the tag’s rules. A value is text or a number, and anything else is dropped, as is a name with capitals in it. Never put anything about the caller in one: that’s what id is for.
ipOptional. The caller’s IP address.
user_agentOptional. The caller’s user agent.
idOptional. Your service’s own word for the caller, as text, such as an account’s number or an MCP session’s id.
clientOptional. The app that called, as text, such as MCP’s clientInfo.name.

Any other field is ignored, and a call is counted at the time fivebar has it. An event needs ip or id, as Who called says. fivebar answers 202, with no body, once it has the event, or with one of the Errors. No answer can be read by a page on another site, so send events from your server alone.

Who called

Send ip, id or both: an event with neither is refused.

Visitors are counted once a day each, as on any site, so over a range they’re visitor-days. Without id, a caller is told apart by ip and user_agent, so everyone calling from one address with one user agent, such as one of an app’s servers, is one visitor. On a site that counts its pages too, someone using both can be two visitors a day, one by their browser and one by your id.

fivebar makes the visitor code from id as it makes a browser’s from its address and user agent, one way, with the site and the day’s secret, and keeps none of the three: see Privacy.

What is counted

A call is a pageview of its name, in Top pages and the Content drilldown, and reaches any page goal it matches. With event, it’s that custom event instead, which, as on a page, makes no visit or visitor of its own, so callers who send only events aren’t counted as visitors.

client is the call’s source, read as a link’s utm_source is: claude or claude.ai is Claude, under AI Assistants, as are Claude’s MCP apps, which call themselves claude-ai and claude-code. A name fivebar doesn’t know, such as cursor, is kept as sent, under Referral. Without it, the source is Direct. See Sources and campaigns.

A server event is never taken for a bot’s, whatever its user agent or network, as your token vouches for it. Traffic the site excludes is still left out.

A call has no browser, operating system, device, speed, time on page or scroll depth, so those panes leave it out. Calls make visits as pages do: a visit of calls alone lasts 0 seconds, and is a bounce if it’s one call.

Calls count towards your plan’s billable pageviews, as pages’ pageviews and events do: see Your trial.

Examples

See Server event examples for curl, Python, Node and an MCP server.

Errors

fivebar checks an event in this order, and the first that applies is the answer. An answer with a body is JSON.

StatusAnswerWhen
405{ "error": "method not allowed" }A request other than a POST. Allow says POST.
401{ "error": "token required" }No Authorization header. Its WWW-Authenticate header asks for a token.
401{ "error": "invalid token" }The header holds no token that can send: it isn’t one, or the token is unknown, revoked or made without Send events, was made in the last minute, or is for no site you own or edit. Its WWW-Authenticate header says so too.
413{ "error": "body too large" }The body is over 64 KiB.
400{ "error": "malformed body" }The body isn’t a JSON object.
400{ "error": "missing fields" }site or name isn’t text, or is empty once trimmed and cut.
404{ "error": "unknown site" }The site isn’t on fivebar, or the token can’t send for it. Both are answered alike.
400{ "error": "bad event" }event isn’t a name a custom event can have, such as one starting with /: see Names.
400{ "error": "bad ip" }ip isn’t one public IP address, such as a range or a private address.
400{ "error": "missing caller" }Neither ip nor id.
202No bodyThe site excludes the caller’s address, network or country, so the call is left out.
503{ "error": "no salt" }The day’s secret for the site’s time zone hasn’t reached fivebar’s server yet. Nothing was counted, so send it again later.
503{ "error": "unavailable" }The event couldn’t be kept just now. Nothing was counted, so send it again later.
202No bodyfivebar has the event.

Check it works

Send an event with the curl example, with your site’s domain: it prints the status. A 202 means fivebar has it, and within a minute or two the call is in the site’s Top pages, under its name.