Skip to content

New: deep research, balance and auto-reload tools in the keyless MCP server. Install in one line

Benchmarks

Measured, with the method

What we measured, how, and on what data. Two kinds of runs feed this page: end-to-end POST /search calls against the live web through a local ContextFetch stack, and offline engine runs on a synthetic corpus written for this repo. Each block names its source file, the method, the sample size and the unit. Competitor latency and quality appear only when they were measured.

live web real queries, real pages · synthetic docs and fixtures written for this repo

1,644ms p50

Search, cold

5 live-web queries, query-cache miss (cache = miss); URL-cache state not recorded, client-observed. Max 2,300 ms.

9ms p50

Same query, cached

The same 5 requests repeated, answered from the query cache. Max 1,842 ms.

69% mean

Context tokens saved

prunedContext vs the whole doc, 29 pairs. Synthetic docs, not live pages.

1.98x

Stored compression

zstd with dictionary, plus base64 in the vector payload. Synthetic held-out docs.

live web

Production API, called from another continent

The same five queries against the live API at api.contextfetch.dev, sent from a client in Florida to the server in Helsinki, so every time includes a transatlantic round trip. Each query is sent once (cold) and once more (repeat, answered from the query cache). 10 results per query with page text and highlights, timed by the client.

Source: results_phase2_prod.json · Run 2026-10-17

Production API latency per query, client-observed, in milliseconds
GroupColdRepeat
python asyncio timeout2,204 ms150 ms
stripe webhook signature verification3,311 ms153 ms
sec edgar apple 10-k revenue table2,809 ms181 ms
qdrant binary quantization benchmarks3,141 ms143 ms
react 19 useActionState example3,531 ms282 ms
QueryCold msRepeat msResults500+ chars
python asyncio timeout2,204150103
stripe webhook signature verification3,311153109
sec edgar apple 10-k revenue table2,809181102
qdrant binary quantization benchmarks3,141143107
react 19 useActionState example3,5312821010
Cold p50 3,141 ms (min 2,204, max 3,531) over 5 queries; repeat p50 153 ms. A repeat is still billed as one search.
live web

Before and after tuning

The same queries and request body against the engine before and after the Phase 2 changes (parallel recall sources, a fetch time budget and caches). Cold runs only. Cold p50 went from 4,140 ms to 1,644 ms.

Source: results_phase2_before.json · Command: .venv/bin/python benchmarks/five_query_bench.py <BASE> <CA_FILE> <before|after> · Date, machine and load are not recorded in this file.

QueryCold ms beforeCold ms afterResults beforeResults after500+ chars before500+ chars after
python asyncio timeout6,3562,3001010710
stripe webhook signature verification4,9491,70451047
sec edgar apple 10-k revenue table3,1121,6335020
qdrant binary quantization benchmarks4,1401,46051049
react 19 useActionState example3,8831,64451045
live web

Recall sources per query

Candidates each recall source returned for the cold run of each query, from contextfetch.sources. A blank cell means the source was not queried for that query.

Source: results_phase2_after.json · Command: .venv/bin/python benchmarks/five_query_bench.py <BASE> <CA_FILE> <before|after> · Date, machine and load are not recorded in this file.

Querystackoverflowwikipediahnsearxnggithublocalarxiv
python asyncio timeout100785100
stripe webhook signature verification101421100
sec edgar apple 10-k revenue table00010
qdrant binary quantization benchmarks000211010
react 19 useActionState example2103510
synthetic

Token pruning

29 fixed question/doc pairs. Each doc is chunked, cross-encoded against the question and pruned with the API defaults; savings compare the pruned context with the whole doc. The docs are synthetic, written for this repo, not live pages, and the questions were written by the same author. Docs average 760.8 tokens and 5.66 chunks.

Source: results.json · Command: .venv/bin/python benchmarks/run_benchmark.py · Run 2026-10-16T22:09:29Z

Tokens saved%
Mean69.5
Median79
Min13.1
Max85.5

Answer kept, % of pairs

top-186.2
top-396.6
pruned93.1
random18

top-1 / top-3: the answer-bearing chunk is the first or among the first three highlights. pruned: the pruned context still contains it. random: the chance a random chunk is the right one.

synthetic

Engine component latency

Wall-clock time around single calls after a warm-up, on the synthetic corpus and hand-written HTML fixtures.

Source: results.json · Command: .venv/bin/python benchmarks/run_benchmark.py · Run 2026-10-16T22:09:29Z

Operationnp50 msp95 msUnit
embed_per_doc150109.6167.49one page (title + first 2,000 Markdown chars) per call
rerank_per_20_chunks87501.45573.3one query x 20 random corpus chunks per call
prune_per_page29136.4173.86chunk + cross-encode + select one corpus doc
html_to_markdown1004.66.97engine page_to_result (trafilatura) per fixture page
Fixture (hand-written)HTML bytesMarkdown charsnp50 msp95 ms
api-ref-ledgerline-payments.html9,8183,746256.227.18
blog-postgres-partial-indexes.html11,7253,303253.193.27
docs-nginx-rate-limiting.html11,5972,773253.283.32
qa-asyncio-blocking-timeout.html8,8041,796256.767.13

Model cold start: embedding model load + first call 104 ms; cross-encoder load + first call 87.1 ms.

synthetic

Storage and vector recall

zstd level 19 on 10 held-out synthetic docs, dictionary trained on 40 others. The stored ratio also counts the base64 encoding used in the vector payload; use it for capacity estimates. Vector bytes: raw bytes = vectors x bytes_per_vector; float32 = dim*4, uint8 = dim, 1-bit = ceil(dim/8); a projection by arithmetic, not a measurement.

Source: results.json · Command: .venv/bin/python benchmarks/run_benchmark.py · Run 2026-10-16T22:09:29Z

CodecRatioBytes
Raw Markdown1x29,187
zstd + dictionary2.64x11,055
zstd, no dictionary2.06x14,152
Stored (dictionary + base64)1.98x14,752
FormatBytes per vector (dim 384)Raw GB at 250,000,000 vectors
float321,536384
uint838496
1-bit4812
Query setQueriesCorpus vectorsbinary onlybinary top-20 + float rescorebinary top-40 + float rescore
held-out doc chunks vs train-doc chunks542060.5220.7170.861
natural-language questions vs all chunks292600.6280.790.903
Recall@10 of 1-bit vectors against exact float cosine on the synthetic corpus. The corpus is small, so a rescoring shortlist covers a large share of it; expect lower recall on millions of vectors.

Machine

The machine the offline engine run used. The end-to-end search files do not record their machine.

Source: results.json · Command: .venv/bin/python benchmarks/run_benchmark.py · Run 2026-10-16T22:09:29Z

ItemValue
CPUApple M2
Logical CPUs8
RAM24 GiB
Load average at start (1 / 5 / 15 min)7.7 / 10.4 / 14.6
OSmacOS-27.0.1-arm64-arm-64bit-Mach-O
Python3.13.3
onnxruntime1.31.0
fastembed0.9.0
zstandard0.25.0
trafilatura2.3.1

Competitors

Competitor latency and quality: not measured (Exa, Tavily in results.json). We publish only what we ran. To compare on your own queries, run benchmarks/run_benchmark.py with --live and your own EXA_API_KEY or TAVILY_API_KEY.

Run the numbers on your own queries

The benchmark scripts are in the repository. Or try the live API in the browser, no key needed.