Reading Captures
The call
const response = await archive.content("https://example.com", { timestamp: "2002" });
const capture = await archive.getContent("https://example.com", { timestamp: "2002" });
capture.timestamp; // "2002-11-29T05:43:48Z"
capture.snapshot; // "https://web.archive.org/web/20021129054348/http://www.example.com:80/"
capture.mime; // "text/html"
capture.bytes; // 339
capture.content; // the decoded body
Reading is a separate operation from listing on purpose. Every provider lists through some CDX like index, but bodies come from an endpoint of the provider's own, and the only rule they share is that it must not return the archive's own UI. Wayback, Archive-It and Webarchiv Österreich replay the original response under the id_ modifier, Arquivo.pt under noFrame/replay, Common Crawl serves a byte range of a WARC file.
Picking the capture
timestamp is a Wayback stamp (YYYY through YYYYMMDDhhmmss) or an ISO date. The provider answers with the newest capture at or before it, or, when it holds nothing that old, the closest capture after it. So the body can postdate the request, and capture.timestamp is the date you should quote, not the one you asked for. Had to reach forward for it? Then capture._meta.selection reads "after". No more comparing timestamps by hand. Without timestamp you get the newest capture.
A snapshot URL works as the target too: pass the snapshot of a listed page and the provider reads that capture. The explorer reads by the original URL and the archive's own stamp instead, which lands on the same capture and does not trip over the :80 old originals carry.
What comes back
interface ArchivedContent {
url: string; // original URL, as the archive recorded it
timestamp: string; // ISO 8601 date of the capture actually returned
snapshot: string; // playback URL the body was read from
content: string; // decoded body, as text
mime?: string; // content type the archive reports
bytes: number; // bytes read, after any cap
sha256?: string; // hex SHA-256 of those bytes
truncated: boolean; // the body was cut off at maxBytes
body?: Uint8Array; // those bytes, only with body: true
_meta: Record<string, unknown>;
}
The body is text. Transfer encodings, content encodings and the charset are handled before you see it. A capture that isn't text decodes lossily, and an image read as text is just noise.
Want the bytes instead? Pass body: true:
const capture = await archive.getContent("https://example.com/logo.png", { body: true });
capture.body; // Uint8Array, the same bytes sha256 hashes
That read skips the cache. A storage driver that writes JSON would hand the bytes back as a plain object. Without body, _meta.rawSnapshot, or the WARC filename, offset and length for Common Crawl, still say where the bytes live.
sha256 hashes the bytes that were read, before the charset touches them. For a whole body it matches sha256sum over curl --compressed on the raw playback URL. So checking a saved copy against a capture doesn't need another read. A truncated body hashes only the part that was read.
A capture of a redirect is returned as recorded, never followed. _meta.status holds its status and _meta.location the destination the site named, cut at 2048 characters, so you can see where a moved page pointed without anything visiting it. The tool header prints both on a status: line.
maxBytes caps the read at 2 MiB by default. A capped body sets truncated: true, which the diff helper carries forward as partial, so a missing sentence in a truncated capture is never reported as a removal.
Who can serve a body
| Provider | Body |
|---|---|
| Wayback Machine | original response, id_ replay |
| Arquivo.pt | original response, noFrame/replay |
| Webarchiv Österreich | original response, id_ replay, one exact URL |
| Vefsafn | original response, id_ replay, one exact URL |
| OSZK Webarchívum | original response, id_ replay under /pywb |
| Archive-It | original response, id_ replay inside the collection |
| Common Crawl | HTTP response from the WARC byte range |
| Memento | the selected TimeMap URI, MemGator proxy as fallback |
| Archive.today | its rendered wrapper page, not the original bytes |
| Conifer, Perma.cc, WebCite | none; content() answers unsupported with the reason |
| New Zealand Web Archive | none; its replay sits behind a bot check, so unsupported too |
With providers.all(), content() tries Wayback, Arquivo.pt, Webarchiv Österreich, Vefsafn, OSZK Webarchívum, Archive.today and Common Crawl in order and returns the first body. It reports which provider served it in _meta.provider.
Text versus markup
The library returns the decoded body as it was served. The agent tools add a rendering step: format=text strips markup from an HTML capture and returns what a reader would see, format=raw keeps the source. The docs explorer exposes both, and the diff accepts either.