Skip to main content
AVOID.NET
← Platform Data

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

Last 24h
1,340
1,164 distinct callers
Last 7d
3,797
2,291 distinct callers
Last 30d
9,793
5,162 distinct callers
All time
21,921
since 2026-08-21
Avg response (30d)
329
milliseconds
p95 response (30d)
572
milliseconds
Origin egress (30d)
196 MB
logged responses only
Error rate (30d)
1.4%
134 responses ≥ 400

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

1,340 requests · 1,164 callers

How complete this is

last 24 hours
100.0%
Classified
0 unclassified
99.9%
Network known
1,339 with an ASN
100.0%
Country known
1,340 located
100.0%
Bytes measured
30 MB

A 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 site
Browsers (external)1,194
1,115 callers · Browser-like UA from somewhere else — a person, or a scraper posing as one
Scripts & HTTP clients60
2 callers · curl / python-requests / axios — deliberate programmatic consumers
AI crawlers40
18 callers · Agent reach — the 'for agents' audience the site is built for
Search engines27
27 callers · Organic discovery / SEO reach
Our own site19
7 callers · A person browsing avoid.net — page loads calling our own API

Named clients

what the caller says it is
ClientClassRequestsCallersLast seen
OkHttpScripts & HTTP clients59118h ago
OAI-SearchBotAI crawlers32101h ago
ApplebotSearch engines25255h ago
ClaudeBotAI crawlers19210h ago
AmazonbotAI crawlers554h ago
BingbotSearch engines227h ago
Meta-ExternalAgentAI crawlers2213h ago
curlScripts & HTTP clients1118h ago
PetalBotOur own site1111h ago

Client-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 hours
/api/v1/investigations/[slug]1,274
95.1% · 1,148 callers · 203ms avg · 289ms p95 · 29.8 MB · 2 errors
/api/requests/[id]15
1.1% · 1 callers · 79ms avg · 144ms p95 · 5.7 KB
/llms.txt14
1.0% · 14 callers · 1ms avg · 10ms p95 · 81.6 KB
/api/v1/investigations/[slug]/audit11
0.8% · 1 callers · 168ms avg · 217ms p95 · 27.6 KB
/api/requests6
0.4% · 1 callers · 319ms avg · 394ms p95 · 1.3 KB
/api/search5
0.4% · 1 callers · 132ms avg · 198ms p95 · 1.3 KB
/api/scan4
0.3% · 1 callers · 2669ms avg · 7940ms p95 · 3.4 KB
/api/scan/[id]3
0.2% · 1 callers · 202ms avg · 233ms p95 · 52.4 KB
/api/v1/mcp3
0.2% · 1 callers · 1ms avg · 2ms p95 · 2.3 KB
/api/v1/feed2
0.1% · 1 callers · 446ms avg · 602ms p95 · 17.8 KB
/api/v1/watchlist2
0.1% · 1 callers · 767ms avg · 1104ms p95 · 6.2 KB
/api/v1/stats1
0.1% · 1 callers · 27ms avg · 27ms p95 · 143 B

Top networks (ASN)

who owns the addresses
AS39872159
AS398721 · 1 callers
AS3690338
AS36903 · 35 callers
Microsoft (Azure)34
AS8075 · 12 callers
AS730328
AS7303 · 24 callers
AS2857326
AS28573 · 22 callers
Apple25
AS714 · 25 callers
AS538422
AS5384 · 21 callers
AS1166420
AS11664 · 19 callers
AS3692520
AS36925 · 20 callers
AS1238919
AS12389 · 19 callers
Amazon AWS19
AS16509 · 2 callers
AS755215
AS7552 · 13 callers

One operator carrying many callers is a fleet, not an audience.

Top countries

coarse, from the edge
BR267
249 callers
AR126
120 callers
US116
77 callers
CA65
6 callers
MA64
61 callers
RU63
59 callers
BD53
53 callers
CL46
43 callers
VE34
32 callers
CO30
27 callers
MX30
30 callers
AE29
27 callers

External referrers

excludes our own pages
web-jade-three-47.vercel.app/14
9 callers

Query shapes

parameter names
(none)1,324
1,164 callers
limit11
1 callers
q5
1 callers

A 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

Requests per hourpeak 144 at 10-12 01:00 UTC
10-05lighter bars = midnight UTC10-12
Requests per day30d observed
09-1310-12

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.

Data refreshes every 5 minutes · All metrics derived from Supabase