Search API latency and source freshness need separate measurements. Latency is the time your request takes to reach a usable result. Freshness concerns the version of information returned. A fast response is not proof that a source was updated recently, and a recently published source is not proof that the API fetched it on this attempt.
Freeze the conditions that affect the result
| Condition | Log explicitly |
|---|---|
| Search context | Query, engine, country, language and supported device/location controls |
| Execution | Concurrency, client region, timeout, retries and cache policy |
| Output validity | HTTP/business status, expected fields and usable-result decision |
| Freshness | Source publication/update evidence, retrieval timestamp and content hash |
| Cost | Attempts and actual charged units, including failures where applicable |
Choose task-representative queries before running providers. Save each raw response and repeat the same requested context. Do not compare one provider’s default country with another’s localized request. If the API does not expose or let you control cache behavior, record that limitation rather than inventing a “cache off” setting.
Produce raw per-attempt records
from datetime import datetime, timezone
from time import perf_counter
def measure_call(query, market, call):
started = datetime.now(timezone.utc).isoformat()
tick = perf_counter()
try:
envelope = call()
if not isinstance(envelope, dict) or envelope.get("code") != 0:
raise ValueError("Business response failed")
data = envelope.get("data")
if not isinstance(data, dict) or not isinstance(data.get("organic"), list):
raise ValueError("Result schema failed")
outcome = {"status":"success", "organic_count":len(data["organic"])}
except Exception as exc:
outcome = {"status":"failure", "error_type":type(exc).__name__}
return {"query":query, "market":market, "request_started_at":started,
"elapsed_ms":(perf_counter()-tick)*1000, **outcome}
if __name__ == "__main__":
# Timing a local stub only; this is not a network latency benchmark.
print(measure_call("example", {"country":"us","language":"en"},
lambda:{"code":0,"data":{"organic":[]}}))
The local stub demonstrates the log format only. It returns an empty but correctly shaped organic list. It does not measure the network, establish API speed, or justify a P50/P95 claim. In a real test, pass a bounded request function that checks HTTP status and saves the raw response. Time retries separately or label the value as complete-workflow time.
Interpret results without hiding failures
Calculate latency percentiles from an explicitly identified successful sample and publish the failure count alongside them. Do not drop timeouts without showing how many were excluded. For freshness, compare a reviewed source version with the retrieved version and retain the evidence for the update timestamp. A SERP snippet date alone can be ambiguous.
Use the typed Go client for implementation and RAG stage timing for end-to-end retrieval attribution. This page supplies a measurement protocol; it does not rank providers or promise a latency level.