Docs · Collectors
Collect from any server
Report requests from any server, edge function or log pipeline by posting them to the HTTP API.
Add the code
Send each request to the HTTP API from your server, edge function or log pipeline.
# Up to 50 events per request. Send after your response, and leave out cookies and credentials.# Skip images, CSS and fonts, but send requests for .js and .mjs files: Ethogram counts the scripts agents fetch.# Send every other request header as received, signature, signature-input and signature-agent included, with the# full URL as requested: signed agents (Web Bot Auth) are verified against them.# Add "action": { "name": "Added to cart", "target": "Blue T-shirt" } to an event to report a named action.# Add "response" with your answer's content-type, content-length and cf-mitigated headers to see why agents get stuck.curl https://ethogram.si/api/e \ -H "Authorization: Bearer $ETHOGRAM_KEY" \ -H "Content-Type: application/json" \ -d '{ "collector": "0.12", "events": [{ "url": "https://example.com/pricing?plan=pro", "method": "GET", "time": "2026-10-10T12:00:00Z", "status": 200, "duration": 42, "ip": "203.0.113.7", "headers": { "user-agent": "Mozilla/5.0 (compatible; GPTBot/1.2; +https://openai.com/gptbot)", "accept": "text/html" }, "response": { "content-type": "text/html; charset=utf-8", "content-length": 48213 } }] }'# Optional browser check: serve https://ethogram.si/ethogram.js at /_ethogram/check.js on your site, add# <script src="/_ethogram/check.js" defer></script> to your pages, and answer each POST to /_ethogram/report with a 204. Then send# its JSON body as the event's "browser" field, with that request's own url, ip and headers:# { "url": "https://example.com/_ethogram/report", "method": "POST", "ip": "203.0.113.7",# "headers": { "user-agent": "Mozilla/5.0 …" }, "browser": { "v": 1, "phase": "load", … } }Set the server key
The code reads your project's server key from the ETHOGRAM_KEY environment variable. Create the key on your project's setup page in the dashboard (or under Settings, Server keys), and set it where your server runs. It's shown once, so save it straight away. Keep it secret, like a password: it lets whoever holds it report events for your site.
The example sends one event. Every field, limit and response is in the HTTP API reference.
What to send
- One event per request your server handled, after the response has gone out, ignoring any error, so visitors never wait or fail on Ethogram.
url: the full URL as requested, with scheme and host.method,time,status,durationandipwhen you have them, andresponse(your answer'scontent-type,content-lengthandcf-mitigated) to see why agents get stuck.ip: the visitor's address as your host reports it, such ascf-connecting-ip,x-real-ipor the lastx-forwarded-forentry. The first entry is only the client's word.
Forwarded headers
Send every request header as received, except cookie, authorization and proxy-authorization. Keep signature, signature-input and signature-agent exactly as they came: signed agents (Web Bot Auth) are verified against them, together with the URL and method, so those must be the request's own.
Skip static assets (CSS, images, fonts, video): they aren't visits. Do send requests for JavaScript files (.js, .mjs): Ethogram counts the scripts each agent fetches, adds them to no request count, and drops people's on arrival.
Named actions
Add "action": { "name": "Added to cart", "target": "Blue T-shirt" } to an event to report a named action. See Named actions with track().
Optional: the browser check
Some AI agents drive a real browser, like Claude in Chrome or Comet. To your server, their requests look like a person's. The browser check is a small script that tells them apart by how each page is used: whether the pointer moved before a click, whether typed text came with key presses, whether the browser says automation controls it. Serve https://ethogram.si/ethogram.js at /_ethogram/check.js on your own domain and add this tag to your pages. Forward each POST to /_ethogram/report as an event with a browser field, as at the end of the example above.
<script src="/_ethogram/check.js" defer></script>Your server answers two paths of its own: /_ethogram/check.js, the script, fetched from https://ethogram.si/ethogram.js and cached for an hour, and /_ethogram/report, where the script sends its counts once when the page loads and again when it's hidden or closed. Each report is forwarded to Ethogram with the request's IP and headers, so it joins the visit it belongs to. Neither path is reported as a page.
It sets no cookie, stores nothing in the browser, and sends only counts and yes-or-no answers: never where the pointer was, what was typed or anything that identifies the person. See Data we keep. Without it, everything else works the same, and most of those agents count as people.
Check it
Deploy, then visit your site the way an AI agent would, with your own domain in place of example.com:
curl -A "GPTBot/1.2" https://example.com/The setup page turns live when the first event arrives. Your test shows up as a spoofed GPTBot, since it doesn't come from OpenAI. That's detection working. Nothing showing up? See the FAQ.