Skip to content
Start free

Source Provenance and Caching

Response headers that show which document a result came from, when it was fetched, and whether it was cached.

When an extraction feeds a decision someone may later need to defend, the result alone is not enough. You also need to show which document produced it and whether it was fresh. Every successful response from /extract/markdown, /extract/json and /generate/json carries that information in response headers, so it never changes the shape of your result.


HeaderExampleMeaning
X-Tabstack-Final-Urlhttps://www.mozilla.org/The URL the source document was served from, after redirects. Can differ from the url you sent.
X-Tabstack-Origin-Status200The HTTP status the origin returned for that document.
X-Tabstack-Retrieved-At2026-11-04T17:52:38ZWhen the document was retrieved from the origin, as an RFC 3339 UTC timestamp.
X-Tabstack-Checksumsha256:17f6426d…48fa7SHA-256 of the source document the response was extracted from. See What the checksum covers.
X-Tabstack-CachemissHow caching produced the response. See Cache status.
Age3Seconds since the cached content was stored. Sent only when cached content was served.
X-Trace-Ida47d0ac0e16e96b2613867f231da10b6The identifier for this request. Quote it when you contact support. Also sent on error responses.

A response looks like this:

HTTP/1.1 200 OK
Content-Type: application/json
X-Tabstack-Cache: miss
X-Tabstack-Checksum: sha256:17f6426dbd14b08ef0bc1fb5c32c8f34461319038841e27e42468534db448fa7
X-Tabstack-Final-Url: https://www.mozilla.org/
X-Tabstack-Origin-Status: 200
X-Tabstack-Retrieved-At: 2026-11-04T17:52:38Z
X-Trace-Id: a47d0ac0e16e96b2613867f231da10b6

Here the request was for http://mozilla.org. The final URL shows the page that was actually read.


The checksum is computed over the exact bytes your result was extracted from, which depends on how the page was fetched:

  • A plain fetch, such as a PDF or a static page, hashes the file as downloaded. If you hold a copy of the file, its SHA-256 matches the checksum when it is the same document Tabstack read.
  • A page rendered in a browser (typical at effort: "max") hashes the rendered page. Scripts, ads and timestamps mean a rendered page can differ on every load, so two fetches of the same URL may produce different checksums even when the visible content is unchanged.

Downloading the page yourself later and comparing hashes proves little on its own, because the source can change between fetches. The checksum is most useful recorded alongside the result at the time of extraction: it identifies which bytes produced that result.


Tabstack keeps two caches: one for fetched pages and one for finished responses. X-Tabstack-Cache tells you which, if either, was used:

ValueMeaning
missThe page was fetched and processed fresh.
fetch-hitThe page came from the fetch cache, and the response was produced fresh from it.
hitThe whole response was served from the response cache.
bypassYou set nocache: true, so no cache was read.

With hit and fetch-hit, X-Tabstack-Retrieved-At is the time the page was originally retrieved, not the time the cached response was served, and the checksum is that of the original document. Age tells you how long ago the content was stored.

When you need a record that the page was read at a specific moment, pass nocache: true. The response then reports bypass and a Retrieved-At of the current request. See Production Reliability for when to bypass the cache.


A header is left out rather than guessed when its value is unknown. In particular, Tabstack never fills in the final URL with the URL you requested.

  • X-Tabstack-Final-Url: not every fetch method can see the URL a page was ultimately served from.
  • X-Tabstack-Origin-Status: a browser fetch that timed out before the page finished loading, but still had usable content, has no status to report.
  • Any provenance header on a cached response: responses cached before a header was introduced are served without it until they expire.

Treat each header as optional in your code.


import Tabstack from "@tabstack/sdk";
interface Provenance {
finalUrl: string | undefined;
originStatus: number | undefined;
retrievedAt: string | undefined;
checksum: string | undefined;
cache: string | undefined;
traceId: string | undefined;
}
// Every header can be absent, so every field may be undefined.
function provenanceFrom(headers: Headers): Provenance {
const get = (name: string) => headers.get(name) ?? undefined;
const status = get("X-Tabstack-Origin-Status");
return {
finalUrl: get("X-Tabstack-Final-Url"),
originStatus: status ? Number(status) : undefined,
retrievedAt: get("X-Tabstack-Retrieved-At"),
checksum: get("X-Tabstack-Checksum"),
cache: get("X-Tabstack-Cache"),
traceId: get("X-Trace-Id"),
};
}
const client = new Tabstack();
// withResponse() returns the raw response alongside the parsed result.
const { data, response } = await client.extract
.markdown({ url: "http://mozilla.org" })
.withResponse();
// Keep the provenance next to the result it describes.
const record = {
content: data.content,
provenance: provenanceFrom(response.headers),
};

The headers are exposed to browsers through CORS, so code running in a web page can read them too.