Wayback Machine Snapshots and Archived Page Content avatar

Wayback Machine Snapshots and Archived Page Content

Pricing

from $0.40 / 1,000 archived snapshots

Go to Apify Store
Wayback Machine Snapshots and Archived Page Content

Wayback Machine Snapshots and Archived Page Content

List every Internet Archive capture of a URL, host or domain from the Wayback Machine CDX index, and optionally pull the archived page text for the latest, earliest or all snapshots.

Pricing

from $0.40 / 1,000 archived snapshots

Rating

0.0

(0)

Developer

Code Craft Colorado

Code Craft Colorado

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

Categories

Share

Find out when the Internet Archive captured a page and what the page said at the time. Give this actor a list of URLs, hosts or whole domains and it returns the matching captures from the Wayback Machine's CDX index, one row per snapshot, with the capture time, HTTP status, content type, compressed size, a content digest and two direct links: the browsable Wayback page and the raw archived copy. Turn on content fetching and it also downloads the archived page and extracts its visible text, for the latest capture of each URL, the earliest, or all of them.

It is built to be left running. Every request goes to the Internet Archive's public CDX and Wayback endpoints over plain HTTP: no API key, no login, no browser, no proxies. The actor identifies itself with a User-Agent that names the operator and a contact address, spaces its requests 500 ms apart, works at most two URLs at a time and retries transient errors with backoff. It reads the index live on every run, so you get whatever the archive holds at that moment, and one URL failing never stops the others.

At a glance

Three consecutive daily captures of apple.com, from a run with fetchContent on and contentMode set to latest. Only the newest row carries text; the two newest rows share a digest, which means the archive stored identical content on both days.

capturedAtstatusCodelengthdigestcontentTextwaybackUrl
2026-09-26T02:58:15Z200442887W6JR7MTQOWG76ALW2DPODITZRH5HS56Apple\nApple\nStore\nMac\niPad\niPhone...https://web.archive.org/web/20260926025815/https://www.apple.com/
2026-09-25T11:53:45Z200442907W6JR7MTQOWG76ALW2DPODITZRH5HS56nullhttps://web.archive.org/web/20260925115345/https://www.apple.com/
2026-09-24T15:31:13Z20044240MGCLIVMS3VKWNIWA7MHYHVQDZLQSAJLGnullhttps://web.archive.org/web/20260924153113/https://www.apple.com/

What data does it extract?

Every row describes one capture. Field names below are exactly as they appear in the dataset.

Which page and when

  • inputUrl: the URL, host or domain exactly as you gave it.
  • original: the URL the archive actually captured. With host or domain matching this varies from row to row; even with exact it is the archive's canonical form, so an input of apple.com comes back as https://www.apple.com/.
  • timestamp: the capture time in the archive's 14-digit YYYYMMDDhhmmss form, UTC.
  • capturedAt: the same instant as ISO 8601, for example 2026-09-26T02:58:15Z. Null only if the index returned a malformed timestamp.

What was captured

  • mimetype: the content type recorded at capture time, such as text/html or application/pdf.
  • statusCode: the HTTP status the archive received when it captured the page. Null when the index has no status for the record.
  • digest: a hash of the captured content. Identical digests mean identical content, so comparing digests across rows tells you which captures actually differ.
  • length: the compressed size of the capture in the archive, in bytes.

Where to see it

  • waybackUrl: the browsable Wayback Machine page for this capture, with the archive's toolbar.
  • rawUrl: the same capture served without the toolbar, using the archive's id_ form. This is what the actor downloads when fetching content.
  • sourceUrl: the same value as waybackUrl, kept for consistency with the other actors in this collection.

The page text, when requested

  • contentText: the visible text of the archived page. Null on rows where content was not requested or not selected by contentMode.
  • contentSkipped: true when content was requested for this row but not fetched, for example a PDF or an image, or a download that failed.
  • contentSkipReason: why it was skipped, such as unsupported mimetype application/pdf, or the error message from a failed download.

Wayback options explained

matchType: what counts as a match

The value is passed straight to the CDX API's matchType parameter.

ValueWhat you get
exactCaptures of this one URL, in the archive's canonical form. Default.
prefixCaptures of this URL and every URL that starts with it, such as everything under /blog/.
hostCaptures of every URL on this hostname.
domainCaptures of every URL on this hostname and all of its subdomains.

collapse: one capture per period

Popular pages are captured many times a day. Collapsing asks the index to keep only the first capture whose timestamp starts with a given number of digits, so consecutive captures within the same hour, day, month or year fold into one row.

ValueTimestamp digits comparedEffect
nonenoneEvery capture the index holds. Default.
hourly10 (YYYYMMDDhh)At most one capture per hour.
daily8 (YYYYMMDD)At most one capture per day.
monthly6 (YYYYMM)At most one capture per month.
yearly4 (YYYY)At most one capture per year.

The index compares each capture with the one before it, and it is ordered by URL and then by time, so with host or domain matching the collapse applies within each URL rather than across the whole site.

timestamp and capturedAt

The archive addresses every capture by a 14-digit UTC timestamp, YYYYMMDDhhmmss; the capture at 20260926025815 was taken on 26 September 2026 at 02:58:15 UTC. The row keeps that string as timestamp, because it is the key you need to build archive URLs, and adds capturedAt as ISO 8601 for sorting and date arithmetic. The from and to inputs use the same digits and accept any prefix from YYYY to the full 14.

waybackUrl versus rawUrl

FieldShapeUse it for
waybackUrlhttps://web.archive.org/web/{timestamp}/{original}Opening in a browser. The archive rewrites links and adds its toolbar.
rawUrlhttps://web.archive.org/web/{timestamp}id_/{original}Programmatic access. The id_ flag returns the archived bytes as captured, without the toolbar or rewriting.

newestFirst and maxSnapshotsPerUrl

maxSnapshotsPerUrl, when set, caps the rows for each input URL after from, to, onlySuccessful and collapse have been applied. newestFirst decides which end of the history that cap keeps, and the row order either way.

newestFirstRows you getHow the index is read
true (default)The most recent captures, newest row first; the most recent maxSnapshotsPerUrl of them when a count is set.One request per URL when a count is set; otherwise the index is walked and the result reversed.
falseOldest row first; the oldest maxSnapshotsPerUrl of them when a count is set.Pages forward through the index with resume keys until the cap is reached or the history ends.

contentMode: which rows get text

Only used when fetchContent is on. Selection happens among the rows returned for each URL, so earliest with newestFirst on means the oldest of the most recent captures, not the oldest capture in the archive. Set newestFirst to false or narrow from and to if you want the true first capture.

ValueText is fetched for
latestThe single most recent row per input URL. Default.
earliestThe single oldest row per input URL.
allEvery row. One download per row, so this is where cost and run time add up.

onlySuccessful

On by default, this sends filter=statuscode:200 to the index so you only see captures where the archive received a normal page. Turn it off to see redirects (301, 302), errors (404, 500) and revisit records, which the archive writes when a capture was byte-identical to an earlier one. Revisit records have no status of their own, so statusCode is null on those rows.

Input

FieldMeaningDefaultWhen to change it
urlsURLs, hosts or domains to look up. Required, at least one, no duplicates.noneAlways.
matchTypeexact, prefix, host or domain.exactSurveying a section, a site or a domain family rather than one page.
fromEarliest capture to include, YYYY to YYYYMMDDhhmmss. With no dates and no count, the actor returns the last 30 days.last 30 daysLimiting the history to a window.
toLatest capture to include, same format.unsetSame.
onlySuccessfulKeep only HTTP 200 captures.trueTurn off to see redirects, errors and revisit records.
collapsenone, hourly, daily, monthly or yearly.nonedaily to thin a busy page; monthly or yearly for a long, sparse timeline.
maxSnapshotsPerUrlStop after this many captures per URL. Applies only when set, and combines with dates to cap a window.noneSet to 1 for "the latest capture".
newestFirstTake the cap from the recent end of the history.trueTurn off to walk forward from the first capture.
fetchContentDownload the archived page and add its text. Charged per page fetched.falseWhenever you need what the page said, not just when it was captured.
contentModelatest, earliest or all.latestall only when you need every version's text.

The latest archived text of a few pages, one row per URL. This is the saved task "Latest archived text of a web page"; schedule it to keep a running record.

{
"urls": ["apple.com", "https://example.com/pricing"],
"maxSnapshotsPerUrl": 1,
"fetchContent": true,
"contentMode": "latest"
}

A change history of one page, one capture per month since 2020, oldest first, with the text of the first capture in the window.

{
"urls": ["https://example.com/pricing"],
"from": "2020",
"collapse": "monthly",
"newestFirst": false,
"maxSnapshotsPerUrl": 200,
"fetchContent": true,
"contentMode": "earliest"
}

Everything the archive holds for a site section, including redirects and errors, without content.

{
"urls": ["https://example.com/blog/"],
"matchType": "prefix",
"collapse": "none",
"onlySuccessful": false,
"maxSnapshotsPerUrl": 5000
}

Listing snapshots costs one request per URL when a count is set with newestFirst on, and a page of index results per few thousand captures otherwise, so a run over a handful of URLs finishes in seconds. Content is one extra request per selected row, and all requests are spaced 500 ms apart, so fetching text for every row of a 1,000-row history takes at least eight to nine minutes plus the archive's own response time.

Output example

One row from the run shown above; contentText is shortened here.

{
"inputUrl": "apple.com",
"original": "https://www.apple.com/",
"timestamp": "20260926025815",
"capturedAt": "2026-09-26T02:58:15Z",
"mimetype": "text/html",
"statusCode": 200,
"digest": "7W6JR7MTQOWG76ALW2DPODITZRH5HS56",
"length": 44288,
"waybackUrl": "https://web.archive.org/web/20260926025815/https://www.apple.com/",
"rawUrl": "https://web.archive.org/web/20260926025815id_/https://www.apple.com/",
"contentText": "Apple\nApple\nStore\nMac\niPad\niPhone\nWatch\nVision\nAirPods\nTV & Home\nEntertainment\nAccessories\nSupport\n0\n+\nGet 3 months of Apple One free with any new iPhone, iPad, or Mac.\n1\nLearn more\niPhone 18 Pro\nPro further.\nLearn more\nBuy\n...",
"contentSkipped": false,
"contentSkipReason": null,
"sourceUrl": "https://web.archive.org/web/20260926025815/https://www.apple.com/"
}

Rows land in the run's default dataset, which you can view in Console under the Snapshots tab or download as JSON, CSV, Excel or XML from the dataset's Export menu and the API. Text extraction drops script, style, noscript and template elements, joins the remaining text with newlines and collapses runs of whitespace, so contentText is ready for search, diffing or a language model without further cleanup.

Errors and edge cases

Anything that fails is recorded in a JSON record named ERRORS in the run's default key-value store, as a list of {"url": ..., "error": ...} objects. The record exists only when something failed, so its absence means a clean run. The run's status message also reports the number of errors. Nothing that fails is charged.

  • URL with no captures. The index returns nothing, the actor writes zero rows for that URL and moves on. This is not an error and appears nowhere in ERRORS.
  • Index request fails. On 429 or 5xx responses and network errors the actor retries up to four more times with 1, 2, 4 and 8 second waits. If the last attempt fails, or the index returns another error immediately, the URL is skipped, an entry goes into ERRORS, the other URLs continue and no row is charged for it.
  • Content download fails. The snapshot row is still written and charged as a row, but with contentSkipped true and the error message in contentSkipReason. The rawUrl and the error also go into ERRORS. The page-content event is not charged.
  • Binary content. PDFs, images, archives and anything else that is not text/* or XHTML are not downloaded. The row has contentSkipped true and contentSkipReason such as unsupported mimetype application/pdf. Not charged as a page fetch.
  • Non-200 captures and revisit records. Hidden by default. With onlySuccessful off they appear as ordinary rows; statusCode is null where the index has no status, as it does for revisit records. Content fetching treats them like any other row, so a revisit record selected by contentMode is skipped as an unsupported type rather than downloaded.
  • Charge limit reached. If the run hits the maximum charge you set, it stops cleanly and keeps every row already written.
  • Empty urls. The run fails immediately with a message and writes nothing.

How much does it cost?

This actor uses pay-per-event pricing with three events.

  • One dataset row per snapshot. Every capture returned counts as one row, whether or not it carries text.
  • page-content, once per page actually fetched. Charged only when fetchContent is on, the row was selected by contentMode, and text was extracted. Skipped binaries, failed downloads and rows outside the contentMode selection are not charged.
  • Actor start, Apify's standard per-run event.

Not charged: URLs with no captures, URLs that failed at the index, retries, the ERRORS record and platform compute, which is included in the event price. The cheapest way to read a page's history is to list it without content and fetch text only for the rows you need; contentMode: "all" on a long history is where cost grows. Current rates are on the Pricing tab of this page.

Use cases

  • Find the month a competitor changed its pricing page and read the previous version.
  • Recover the text of pages, documentation or announcements that have since gone offline.
  • Build a change timeline for a URL by grouping rows on digest and keeping the first capture of each distinct value.
  • Check how often a site or domain is being archived and which of its URLs are covered.
  • Keep a running record of a page on a schedule, one new row per day, for compliance or research.
  • Give an AI agent a tool for questions like "what did this page say in 2021?".

Run it on a schedule, from the API, or from an agent

Create a schedule in Apify Console to run the actor daily or weekly and read the results from the dataset, or start runs from the Apify API and the JavaScript and Python clients with the same input JSON shown above. The actor is also available through Apify's MCP server, so an agent can call it as a tool. Inputs are identical everywhere, and the saved task "Latest archived text of a web page" is a ready-made starting point for a scheduled record.

All four run against official public APIs with no proxies or credentials.

FAQ

Is this legal? Yes. The Wayback Machine is a public archive operated by the Internet Archive, and its CDX index and archive URLs are public endpoints. This actor identifies itself with a User-Agent that names the operator and a contact address, spaces requests 500 ms apart, works at most two URLs at a time, retries with backoff rather than hammering, and downloads only the pages you ask for. What you do with archived content of a third party's site is governed by that content's copyright as it would be if you read it in a browser.

Why do I get fewer rows than expected? Three inputs thin the history: collapse keeps one capture per period when set, onlySuccessful drops redirects, errors and revisit records, and with no dates and no count only the last 30 days are returned. Set from, turn onlySuccessful off and leave collapse at none to see everything the archive holds.

Why is original different from the URL I entered? The index matches on the archive's canonical form of a URL, so apple.com matches captures stored as https://www.apple.com/. inputUrl always keeps what you typed; original tells you what was actually captured.

Why is contentText null on most rows? Text is fetched only for the rows selected by contentMode, which by default is the latest capture per URL. Other rows keep contentSkipped false and contentText null because content was never requested for them. Rows where content was requested but could not be fetched have contentSkipped true and a reason.

Can I get the archived HTML instead of the text? Not from this actor; it returns extracted text. Every row carries rawUrl, which serves the archived bytes exactly as captured, so you can download the HTML yourself for any capture you care about.

Does it save new pages to the archive? No. It only reads the index and existing captures. It never asks the Wayback Machine to capture anything.

How do I tell which captures actually changed? Compare digest. In the sample above the captures of 26 and 25 September share a digest, so the page was byte-identical on both days, while the 24 September capture differs.

Do I need an API key, a proxy or a browser? No. All requests are plain HTTP to the Internet Archive's public endpoints from Apify's own infrastructure.

What happens when the Wayback Machine is slow or returns errors? Requests use a 60 second timeout and retry on 429 and 5xx responses and network failures, five attempts in total with exponential backoff. A URL that still fails is recorded in ERRORS, not charged, and does not stop the rest of the run.

Something is missing or wrong? Open an issue on this actor's Issues tab with the input you used and the run ID, and it will be looked at.