When a multi-page request to the Extract API (POST /api/v1/extract)
includes one page the crawler cannot fetch in time, the response is
HTTP 200 with "data": [] — the pages that would have extracted
successfully are silently dropped along with the failing one, and there
is no per-page error to indicate what happened.
Repro (any API key):
# 1. This page extracts fine on its own:
curl -s -X POST https://kagi.com/api/v1/extract \
-H "Authorization: Bearer $KAGI_API_KEY" -H "Content-Type: application/json" \
-d '{"pages":[{"url":"https://simonwillison.net/2026/Jul/24/introducing-claude-opus-5/"}],"format":"json"}'
# -> data: [{url, markdown}] with full content
# 2. This page times out crawling (~10s), alone it yields data: []:
curl -s -X POST https://kagi.com/api/v1/extract \
-H "Authorization: Bearer $KAGI_API_KEY" -H "Content-Type: application/json" \
-d '{"pages":[{"url":"https://code.claude.com/docs/en/changelog"}],"format":"json"}'
# -> {"meta":{...,"ms":10005},"data":[]}
# 3. Batch of both: the good page vanishes too:
curl -s -X POST https://kagi.com/api/v1/extract \
-H "Authorization: Bearer $KAGI_API_KEY" -H "Content-Type: application/json" \
-d '{"pages":[{"url":"https://simonwillison.net/2026/Jul/24/introducing-claude-opus-5/"},{"url":"https://code.claude.com/docs/en/changelog"}],"format":"json"}'
# -> {"meta":{...,"ms":10002},"data":[]} (HTTP 200, no error anywhere)
Expected: the batch response should contain the successful page's
markdown plus a per-page error entry for the failed one — the API
already has that shape for other failure modes, e.g. extracting
https://example.com/ returns
data: [{url, error: "No data returned from crawlers! ..."}].
Observed: data: [] with meta.ms ≈ 10000 and HTTP 200, so callers
cannot tell a total failure from an empty-content page, and successful
extractions in the batch are lost (and, presumably, still crawled).
Sample trace from a failing 3-URL batch on 2026-08-03:
meta.trace = "ce73f5f3a825f9698f7a91f38065a706", ms = 10015,
node = "us-east4".
Found while debugging an MCP wrapper that batched up to 10 URLs per
call; one JS-heavy page in each batch made every call come back empty
for a month before we spotted it. Workaround on our side: one request
per URL.