API Usage
Who calls the public API, how often, and what they ask for
What is counted
Origin requests only. Responses served from the edge cache (the v1 endpoints are cached for 300s) never reach the server and cannot be counted here, so real client-side traffic is higher than these figures. Callers are identified by a salted daily hash of their IP — no addresses are stored, and a caller cannot be followed across days.
Alongside that hash we record the network operator (ASN) and country the request came from, the endpoint requested, the page that referred it, and the browser or bot name the client declares about itself. None of these identify an individual: an ASN covers an entire network operator and a country is a country. The IP address itself is discarded after that lookup, as before, and the finer-grained city and postal-code signals our host also offers are deliberately not read.
We also record what was asked for. Query parameters are stored with their values — so a search records the search term, and an address lookup records the address looked up, and an MCP tool call records the tool and the entity it asked about. This is deliberate: what gets queried against a public risk index is part of the record it exists to keep. It is kept two ways, and they differ in the way that matters. On the request log the values sit next to the daily caller hash, and both are deleted after 90 days — that window exists so a single caller pulling thousands of addresses can be spotted. Beyond it we keep only the distinct values themselves, with a first-seen, last-seen and a count, in a table that has no caller column at all. That archive is a permanent record of what has been looked up, never of who looked it up. Daily traffic totals are likewise kept indefinitely.
Volume
Most recent request 48m ago
Unusual volume
2026-10-11 served 1,250 requests — 4.2× the trailing 7-day median of 301 (flagged above 2×). Switch the breakdown below to 24h and check the client, network and endpoint panels; the hourly histogram says whether it arrived as a wall (a crawler sweep) or a hill (a link going around).
Who, what, and from where
How complete this is
last 24 hoursA low Classified figure means the signature list needs a new entry. A zero Network known means the edge is not sending an ASN header at all — not that no cloud traffic arrived.
Who is calling
1.4% of it is our own siteNamed clients
what the caller says it isClient-declared and never verified — a User-Agent is a string the caller chooses. Checking a claimed crawler against its published IP ranges is not implemented.
Which endpoints
last 24 hoursTop networks (ASN)
who owns the addressesOne operator carrying many callers is a fleet, not an audience.
Top countries
coarse, from the edgeExternal referrers
excludes our own pagesQuery shapes
parameter namesA caller that starts sending limit,page where it used to send none is walking the corpus. Grouped by parameter NAME: the values are stored, but grouping on them would give one row per distinct search term.
When
How this is measured
Every public read endpoint is wrapped in withApiLogging(), which records one row per origin request after the response is sent. Logging never blocks or fails a request.
Identity. There is no consumer API key system, so a caller is identified as sha256(salt + IP + UTC date). Distinct-caller counts are counts of that hash. Raw IP addresses are not stored — the column was dropped in migration 034.
Endpoints are grouped by templated route, so /api/v1/investigations/[slug] is one row rather than one row per investigation.
Aggregates are computed in Postgres, not by scanning rows in the app — PostgREST silently caps an unbounded select at 1,000 rows, which has produced wrong figures on this site before.
Egress is the summed size of logged responses (content-length, or the body measured after the response is sent). It covers only these logged routes — page renders and edge-cache hits are not included — so treat it as a floor on Supabase egress, not a total.
Client names come from the User-Agent, matched against a signature list kept as data in lib/client-signatures.json. A User-Agent is a string the caller chooses, so a name here is a claim, not a verified identity; checking a claimed crawler against its published IP ranges is not implemented. The one field that is not taken from the User-Agent is our own site: our pages tag their API calls with an X-AVOID-Client header, because a rule based on the User-Agent would be trivially spoofable and would then overstate our own traffic.
Network and country arrive as request headers from the edge, which resolves them from the IP before our code runs — so no lookup happens here and no address is handled. Both are coarse on purpose. Where the edge sends no ASN header the figure is absent, and the coverage tile says so rather than letting an empty panel read as “no cloud traffic”.
Retention. Raw rows are kept 90 days and then deleted. Two things are lifted out of them first and kept indefinitely: the day's counts, and the distinct query values with a first-seen, last-seen and a count. The rollup runs before the delete, so a failure there deletes nothing; the value archiving is not a step before the delete but part of the same statement, so a row cannot be removed without its values being kept and cannot be counted twice. The all-time counter reads the archived days and the live rows together, so it keeps counting the whole record instead of shrinking to the retention window once the first purge runs.