# Wayback Machine Snapshots & Archived Text (No Login) (`cliqtomedia/wayback-machine-snapshots`) Actor

List Wayback Machine captures of a URL, URL prefix or whole domain with date, archived link, HTTP status, MIME type and digest. Optional archived page title and text. Date range, dedupe and status filters. No login.

- **URL**: https://apify.com/cliqtomedia/wayback-machine-snapshots.md
- **Developed by:** [Cliqto Media](https://apify.com/cliqtomedia) (community)
- **Categories:** SEO tools, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.42 / 1,000 snapshots

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Add a URL, a URL prefix or a whole domain. The Actor reads the Internet Archive [Wayback Machine](https://web.archive.org/) index and returns one row for each capture: date, snapshot link, HTTP status, MIME type and content digest. It can also return the archived page title and visible text.

It is for SEO and OSINT work: page history, deleted content, old titles, and the list of URLs a site had. The smallest run is one site with 20 captures and takes about 10–30 seconds. No login and no API key.

![Wayback Machine Snapshots: add URLs or a domain, get a table of archived captures with dates, HTTP status, digest and optional page text](https://api.apify.com/v2/key-value-stores/QCLQi1Vsr4HDkdrK2/records/README-BANNER-20261017.png)

### Table of contents

- [What it does](#what-it-does)
- [How it works](#how-it-works)
- [Quick start](#quick-start)
- [Use cases](#use-cases)
- [Input](#input)
- [Output](#output)
- [Pricing](#pricing)
- [Limits](#limits)
- [API, export and integrations](#api-export-and-integrations)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)
- [Related Actors](#related-actors)
- [Support](#support)

### What it does

The Actor asks the public [Wayback Machine CDX index](https://github.com/internetarchive/wayback/tree/master/wayback-cdx-server) which captures exist for each input. It saves each capture as one row in the Dataset. When you turn on **Include archived page text**, it also downloads the raw archived page (without the Wayback toolbar) and returns its `title` and visible `text` with paragraphs.

If a URL has no captures for your filters, you get one `not_found` row for it. You do not get an empty table that looks like a failure. If the archive fails for a URL, you get an `error` row, which is free. If a site is excluded from the archive, you get a free `error` row with `errorCode: SOURCE_EXCLUDED` and the run goes on.

#### What data you get

| Data | Where it comes from | Fields |
| --- | --- | --- |
| Capture index | Wayback Machine CDX index | `originalUrl`, `urlKey`, `timestamp`, `capturedAt`, `statusCode`, `mimeType`, `digest`, `length` |
| Archived link | built from the capture | `snapshotUrl` |
| Page title and text (optional) | the raw archived page | `title`, `text`, `textLength`, `textTruncated`, `contentStatus` |
| Result status | the Actor | `status`, `statusReason`, `errorCode`, `sourceUrl`, `fetchedAt` |

Only public archive data is returned. No account data, cookies or personal profiles.

#### Good fit

- **SEO page history:** see when a page was first captured, how its HTTP status changed (200 → 301 → 404), and what the old title and text said.
- **Recover deleted content:** get the visible text of an old version of a page by date.
- **OSINT and site mapping:** list the archived URLs of a site or all its subdomains with **Deduplicate** set to one per URL (`collapse: urlkey`).
- **Change detection:** keep only captures where content changed with **Deduplicate** set to "Only when content changed" (`collapse: digest`).

#### Not a fit

- It does not take screenshots and does not download images, scripts or PDFs: it can list their captures (**File types**), but saves no files. Text is extracted only from successful (2xx) HTML or plain-text captures.
- It does not search archive.org collections, books or media items. It works with the Wayback Machine web capture index only.
- The archive does not have every page or every day. Missing captures mean the archive has none, not that the page did not exist.
- E-mail addresses and phone numbers in archived text are replaced with `[email removed]` and `[phone removed]`. Phone masking covers international numbers (`+44 20 7946 0958`) and common national formats (`(555) 123-4567`, `555-123-4567`, `020 7946 0958`); unusual formats can stay.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### How it works

1. You add URLs, URL prefixes or domains, and optional dates and filters.
2. The Actor asks the public Wayback Machine index which captures exist, at most one request per second, and keeps the captures that match your filters.
3. For each capture it saves one Dataset row with the date, the archived link, the HTTP status and the content hash. With page text on, it also opens the archived page and saves its title and visible text.
4. A URL without captures gets one `not_found` row. A URL the archive cannot answer gets a free `error` row. The run summary (`RUN_SUMMARY`) shows the counts and why the run stopped.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Quick start

[![Input form: box 1 is the URLs or domains field with apify.com, box 2 is Max snapshots per URL set to 20, box 3 is the optional Archived page text section](https://api.apify.com/v2/key-value-stores/QCLQi1Vsr4HDkdrK2/records/quick-start-form-20261028.png)](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)

1. Open the **Input** tab. Keep the prefilled **URLs or domains** value `apify.com`, or add your own site, for example `wikipedia.org` (box 1 in the picture).
2. Keep **Max snapshots per URL** at the prefill `20` (box 2). Without the prefill the default is `100`.
3. Optional: open **Archived page text** and turn on **Include archived page text** to also get the old title and text (box 3). Leave it off for the first run.
4. Click **Start**.
5. Open the **Output** tab and check the **Snapshots** view: `capturedAt`, `snapshotUrl`, `statusCode` and `mimeType` (boxes 1–3 in the table picture).

   [![Output table: Snapshots view of the prefill run with capture date, archived link and HTTP status columns](https://api.apify.com/v2/key-value-stores/QCLQi1Vsr4HDkdrK2/records/output-table-20261028.png)](https://api.apify.com/v2/key-value-stores/QCLQi1Vsr4HDkdrK2/records/output-table-20261028.png)

Expected result: 20 rows for apify.com, oldest capture first, each with a working link to the archived page.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Use cases

| Buyer job | Input path | Output entity | Key fields | Next integration |
| --- | --- | --- | --- | --- |
| Page history by month | `urls`, `collapse: month` | capture row | `capturedAt`, `statusCode`, `snapshotUrl` | spreadsheet export |
| Old title and text | `urls`, `includeContent: true`, `statusFilter: 2xx` | capture row with text | `title`, `text`, `textLength` | content diff, LLM |
| All archived URLs of a site | `urls: ["*.apify.com"]`, `collapse: urlkey` | one row per URL | `originalUrl`, `capturedAt` | crawl list, link audit |
| Content changes only | `urls`, `collapse: digest` | changed captures | `digest`, `capturedAt` | change log |

#### Scheduling and monitoring

Use an Apify schedule to check a page or a site regularly. Set **From date** to a recent date and **Deduplicate** to "Only when content changed" (`collapse: digest`) to get only captures with new content. Each run is independent: the Actor does not remember earlier runs, so compare `digest` or `capturedAt` with your last export.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Input

#### Input fields

| Field | Plain name | Type | Required | Default / prefill | Allowed values | Effect | Example | Recommendation |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `urls` | URLs or domains | array of strings | yes | prefill `["apify.com"]` | 1–100 http(s) URLs or domains | what to look up | `apify.com/blog/*` | `path*` = every URL under the path, `*.domain` = domain with subdomains |
| `matchType` | Match | string | no | `exact` | `exact`, `prefix`, `host`, `domain` | how wide each URL matches | `domain` | a `*` in the URL overrides it for that entry |
| `from` | From date | string | no | empty (first capture) | `2015`, `2015-06`, `2015-06-01`, `20150601` | earliest capture date, UTC | `2020` | |
| `to` | To date | string | no | empty (latest capture) | same formats, inclusive | latest capture date, UTC | `2020-12` | `2020` means up to the end of 2020 |
| `collapse` | Deduplicate | string | no | `none` | `none`, `digest`, `hour`, `day`, `month`, `year`, `urlkey` | keep one capture per period, per changed content or per URL | `month` | `urlkey` for site URL lists |
| `statusFilter` | HTTP status | string | no | `any` | `any`, `2xx`, `3xx`, `4xx`, `5xx` | keep one status class | `2xx` | `2xx` before asking for text |
| `onlyHtml` | HTML pages only | boolean | no | `false` | true / false | skip images, scripts, PDFs | `true` | use with prefix and domain |
| `mimeTypes` | File types | array of strings | no | empty (all types) | up to 20 MIME types; a value ending in `/` keeps the whole family | keep only captures of these file types | `["application/pdf"]`, `["image/"]` | find archived PDFs or images of a site; not together with **HTML pages only** |
| `sortOrder` | Order | string | no | `oldest` | `oldest`, `newest` | which captures come first | `newest` | `newest` works for exact URLs only |
| `maxSnapshots` | Max snapshots per URL | integer | no | `100` (prefill `20`) | 1–10000 | stop after this many captures for each input | `500` | each capture row is one paid result |
| `includeContent` | Include archived page text (section **Archived page text**) | boolean | no | `false` | true / false | also download the archived page | `true` | slower: about 2–4 s per page, at most 300 pages per run |
| `maxContentChars` | Max text characters | integer | no | `5000` | 100–100000 | cut text per capture | `20000` | `textLength` still shows the full length |

Empty `urls` is rejected with a clear message. One invalid entry (for example `ftp://...`) stops the run before any lookup; only the start fee is charged. Duplicate inputs (`http`/`https`, `www.`, a root `/`, letter case) are looked up once.

#### Interacting settings

| When | Input A | Input B | Effective behavior | Example | Cost/result effect |
| --- | --- | --- | --- | --- | --- |
| A URL ends with `*` or starts with `*.` | `urls` | `matchType` | the wildcard wins for that entry | `apify.com/store*` → prefix | none |
| Newest first | `sortOrder: newest` | `matchType` | allowed for exact URLs only | `apify.com` | none |
| Text for non-2xx captures | `includeContent` | `statusFilter` | redirects, errors and revisit records get `contentStatus: skipped_not_2xx` and no text | `statusFilter: any` | no text fee for skipped rows |
| Only some file types | `mimeTypes` | `onlyHtml` | use one of them; both together stop the run with an input error | `mimeTypes: ["text/html", "application/pdf"]` | only the start fee for the input error |
| Many captures with text | `includeContent` | `maxSnapshots` | text stops after 300 pages per run, later rows get `skipped_limit` | 20 sites × 100 | no text fee after the limit |

#### Input examples

##### Page history with text, one capture per year

```json
{
  "urls": ["apify.com"],
  "from": "2019",
  "to": "2024",
  "collapse": "year",
  "statusFilter": "2xx",
  "maxSnapshots": 10,
  "includeContent": true,
  "maxContentChars": 2000
}
```

Expected behavior: one successful capture per year from 2019 to 2024, each with title and text.
Expected output: rows with `capturedAt`, `snapshotUrl`, `statusCode: 200`, `title`, `text`.
Limit or cost note: start fee + 6 × (capture + text) at the prices below.

##### All archived pages of a domain

```json
{
  "urls": ["*.apify.com"],
  "collapse": "urlkey",
  "onlyHtml": true,
  "maxSnapshots": 1000
}
```

Expected behavior: one row for each distinct archived HTML URL on the domain and its subdomains.
Expected output: `originalUrl`, `capturedAt` (first capture of that URL), `statusCode`.

##### Archived PDFs and images of a site

```json
{
  "urls": ["apify.com/*"],
  "mimeTypes": ["application/pdf", "image/"],
  "collapse": "urlkey",
  "maxSnapshots": 200
}
```

Expected behavior: one row for each distinct archived PDF or image URL under apify.com.
Expected output: `originalUrl`, `mimeType` (for example `image/png`), `capturedAt`, `snapshotUrl` (opens the archived file).
Limit or cost note: rows only, no page text for these files (`contentStatus: skipped_not_text` if text is on).

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Output

#### Output fields

| Field | Meaning | Type | Can be empty? | Example / enum | Source / notes |
| --- | --- | --- | --- | --- | --- |
| `inputUrl` | your input entry | string | no | `apify.com` | as you typed it |
| `matchType` | how it was matched | string | no | `exact` | after wildcard rules |
| `originalUrl` | the URL the archive captured | string | null on `not_found` | `https://apify.com/` | CDX `original` |
| `urlKey` | archive URL key | string | null on `not_found` | `com,apify)/` | CDX `urlkey` |
| `timestamp` | capture time, 14 digits | string | null on `not_found` | `20240115083000` | UTC |
| `capturedAt` | capture time | ISO string | null on `not_found` | `2024-01-15T08:30:00Z` | UTC |
| `snapshotUrl` | link to the archived page | string | null on `not_found` | `https://web.archive.org/web/20240115083000/https://apify.com/` | replay link |
| `statusCode` | archived HTTP status | integer | yes | `200`, `301` | `null` for revisit records without a status |
| `mimeType` | archived content type | string | yes | `text/html` | |
| `digest` | content hash (SHA-1, base32) | string | yes | `2C5…` | same digest = same content |
| `length` | archive record size, bytes | integer | yes | `14231` | compressed record, not page size |
| `title` | archived page title | string | yes | `Apify: Full-stack web scraping` | only with text |
| `text` | archived visible text | string | yes | `Web scraping…` | e-mails and phones masked |
| `textLength` | full text length before the cut | integer | yes | `8312` | |
| `textTruncated` | text was cut | boolean | yes | `true` | |
| `contentStatus` | text result | string | no | `not_requested`, `ok`, `empty`, `skipped_not_text`, `skipped_not_2xx`, `skipped_limit`, `unavailable`, `error` | |
| `status` | row result | string | no | `complete`, `partial`, `not_found`, `error` | |
| `statusReason` | short note | string | yes | `The Wayback Machine has no captures for this URL.` | |
| `errorCode` | error code | string | yes | `SOURCE_UNAVAILABLE`, `SOURCE_EXCLUDED` | only on `error` rows |
| `sourceUrl` | archive index request that produced the row | string | no | `https://web.archive.org/cdx/search/cdx?url=apify.com&…` | provenance |
| `fetchedAt` | when the Actor read it | ISO string | no | `2026-10-17T08:37:10Z` | |

`null` means the archive did not give the value. It is never replaced with `0` or an empty string.

#### Output entities and surfaces

| Situation | Dataset/API/KVS/live view | Result shape | User action |
| --- | --- | --- | --- |
| Normal item | Dataset, views **Snapshots** and **Page text** | one row per capture, `status: complete` | open `snapshotUrl` or export |
| Domain-empty result | Dataset | one row per input, `status: not_found`, capture fields `null` | widen dates, filters or `matchType` |
| Partial result | Dataset | `status: partial`, `contentStatus: unavailable` or `error`, capture fields filled | the archive did not return the page text; the capture data is still valid |
| Technical failure or retry | Dataset + KVS `RUN_SUMMARY` | `status: error` row (free), rows saved before the failure stay; run status SUCCEEDED when fewer than half of the URLs failed and all were looked up, otherwise FAILED | run the failed URLs again later |

`RUN_SUMMARY` in the default key-value store shows the run status, the reason, counts, and per input: captures, first and last date, and `moreAvailable` when more captures exist beyond `maxSnapshots`.

#### Output example

Input: the first example above. One of its 6 rows from a real run; `text` is shortened here.

```json
{
  "inputUrl": "apify.com",
  "matchType": "exact",
  "originalUrl": "https://www.apify.com/",
  "urlKey": "com,apify)/",
  "timestamp": "20190102020849",
  "capturedAt": "2019-01-02T02:08:49Z",
  "snapshotUrl": "https://web.archive.org/web/20190102020849/https://www.apify.com/",
  "statusCode": 200,
  "mimeType": "text/html",
  "digest": "27TX5UTLMOMOW6O2BSAYXOR4RR73LSCN",
  "length": 10491,
  "title": "Web Scraping, Data Extraction and Automation - Apify",
  "text": "Library Docs Pricing Case studies About Contact Log in Sign up Go to app The web…",
  "textLength": 6840,
  "textTruncated": true,
  "contentStatus": "ok",
  "status": "complete",
  "statusReason": null,
  "errorCode": null,
  "sourceUrl": "https://web.archive.org/cdx/search/cdx?url=apify.com&output=json&fl=urlkey%2Ctimestamp%2Coriginal%2Cmimetype%2Cstatuscode%2Cdigest%2Clength&from=2019&to=2024&collapse=timestamp%3A4&filter=statuscode%3A2..&limit=10&showResumeKey=true",
  "fetchedAt": "2026-10-17T10:33:45Z"
}
```

#### Use case → fields

| Buyer job | Input path | Output entity | Key fields | Next integration |
| --- | --- | --- | --- | --- |
| When a page first appeared | `urls`, `sortOrder: oldest`, `maxSnapshots: 1` | first capture row | `capturedAt`, `snapshotUrl` | domain age check |
| Status history (200 → 301 → 404) | `urls`, `collapse: month` | capture rows | `capturedAt`, `statusCode`, `mimeType` | SEO audit sheet |
| Old title and text by date | `urls`, `from`, `to`, `includeContent: true`, `statusFilter: 2xx` | capture row with text | `title`, `text`, `textTruncated` | content diff, LLM |
| Pages a site used to have | `urls: ["*.apify.com"]`, `collapse: urlkey`, `onlyHtml: true` | one row per URL | `originalUrl`, `capturedAt`, `statusCode` | redirect map, link audit |
| Old PDFs and images of a site | `urls: ["apify.com/*"]`, `mimeTypes: ["application/pdf", "image/"]` | one row per file capture | `originalUrl`, `mimeType`, `snapshotUrl` | file recovery list |

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Pricing

#### Pricing unit

You pay per event. Platform usage is included in the price.

| Event | Price | When it is charged |
| --- | ---: | --- |
| Actor start | $0.0025 | once per run for each GB of run memory; the default 256 MB counts as one start |
| Capture row (`snapshot`) | $0.0006 | each saved capture row |
| Page text (`snapshot-text`) | $0.0005 | each capture with extracted text (`contentStatus: ok`) |
| URL with no captures (`not-found`) | $0.0006 | each input with no captures for your filters |

Bronze, Silver and Gold Store plans pay 10%, 20% and 30% less for rows, text and URLs with no captures (Gold: $0.00042 per row or per URL with no captures). The start fee is the same for every plan.

| Capture rows (no text) | Free plan | Gold plan |
| ---: | ---: | ---: |
| 1 | $0.0031 | $0.0029 |
| 10 | $0.0085 | $0.0067 |
| 100 | $0.0625 | $0.0445 |

The flat start fee matters most in tiny runs: with fewer than about 6 captures, most of the cost is the start fee. Put several URLs in one run instead of one run per URL.

`error` rows, skipped text, pages without visible text (`contentStatus: empty`) and rows over your **Maximum cost per run** limit are not charged. An invalid input pays only the start fee. When the run reaches your cost limit, it stops, keeps the saved rows and ends as SUCCEEDED with `reason: CHARGE_LIMIT` in `RUN_SUMMARY`.

#### Cost examples

| Scenario | Input scope | Expected item/event count | Base charge | Optional charge | Stop/cap behavior |
| --- | --- | ---: | ---: | ---: | --- |
| Prefill | `apify.com`, 20 captures | 20 rows | $0.0025 + 20 × $0.0006 = $0.0145 | none | stops at 20 |
| Page text | 4 sites × 25 captures with text | 100 rows + 100 texts | $0.0025 + $0.06 = $0.0625 | $0.05 | text stops at 300 pages |
| Big list | `apify.com/*`, 1,000 captures | 1,000 rows | $0.0025 + $0.60 = $0.6025 | none | stops at `maxSnapshots` |
| No captures | 1 URL the archive does not have | 1 `not-found` | $0.0025 + $0.0006 = $0.0031 | none | — |

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Limits

- Up to 100 URLs per run and 10,000 captures per URL. 10,000 captures cost $6.0025 at the base price, so raise **Maximum cost per run** for such runs.
- Page text for up to 300 captures per run, at most one archived page every 2 seconds; only the first 3 MB of a page are read (then `textTruncated: true`).
- The Actor is polite to the archive: at most 1 request per second. The first "too many requests" answer from the archive index stops all lookups; saved rows stay.
- URLs with no captures are slow to confirm: the archive can take 5–40 seconds per such URL, and the Actor checks three at a time. 99 such URLs took 4–12 minutes in our tests.
- A `partial` row means the capture is real but the archive did not return its page text. You pay for the row, not for the text.
- A run with 100 URLs takes about 15–20 minutes (default timeout 30 minutes). 100 URLs × 3 captures with text (283 texts) took about 17 minutes.
- If one URL fails (for example a very large site the archive cannot list in time), it gets a free `error` row and the other URLs go on. The run still SUCCEEDS with `reason: SOME_URLS_FAILED` when fewer than half of the URLs failed.
- If the archive keeps failing, the run stops after two failed URLs in a row. Inputs not looked up get a free `error` row with `statusReason: Not looked up`, and the run ends as FAILED with the saved rows kept.
- A run stops listing after about 58 minutes, or 15 seconds before its own timeout, whichever comes first. Saved rows stay; `RUN_SUMMARY` shows `reason: DEADLINE`.
- One archive index answer can be at most 16 MB and must come within 90 seconds; one archived page within 45 seconds. A slower answer gives an `error` (index) or `partial` (text) row.
- After 3 archived pages in a row fail (or one "too many requests" answer), the Actor stops fetching page text for the rest of the run and keeps listing captures. Later rows get `contentStatus: skipped_limit` with the reason in `statusReason`, and no text fee.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### API, export and integrations

- **API:** start a run with the Apify API or client (`POST /v2/acts/cliqtomedia~wayback-machine-snapshots/runs`) with the same JSON input; read rows from the run's default Dataset.
- **Scheduling:** see [Scheduling and monitoring](#scheduling-and-monitoring).
- **Export:** download the Dataset as JSON, CSV, Excel or XML from the **Output** tab or the Dataset API.

#### Use with AI agents (MCP)

- MCP server URL with only this Actor: `https://mcp.apify.com?tools=cliqtomedia/wayback-machine-snapshots`.
- Smallest useful input: `{"urls": ["apify.com"], "maxSnapshots": 20}`.
- Key output fields: `capturedAt` (capture time, UTC), `snapshotUrl` (archived page link), `statusCode` (archived HTTP status, `null` for revisit records), `status` (`complete`, `partial`, `not_found`, `error`), `text` (archived visible text when `includeContent` is true).
- Typical run: 10–30 seconds and $0.0145 for 20 captures; with text, about 2–4 seconds and $0.0011 per page. Limits: 100 URLs, 10,000 captures per URL, 300 texts per run.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Troubleshooting

#### Every row is `not_found`

Symptom: one `not_found` row per URL.
Likely reason: the archive has no captures for that exact URL and filters.
Check: open `https://web.archive.org/web/*/<your URL>` in a browser.
Action: remove `from`/`to`, `statusFilter`, `onlyHtml` or `mimeTypes`, or use `matchType: prefix` or `domain`.

#### Text is empty for many rows

Symptom: `contentStatus` is `skipped_not_2xx` or `skipped_not_text`.
Likely reason: those captures are redirects, errors, revisit records or non-HTML files.
Check: the `statusCode` and `mimeType` of the row.
Action: set `statusFilter: 2xx` and `onlyHtml: true`.

#### The run stopped with `RATE_LIMITED` or `SOURCE_ERROR`

Symptom: run status FAILED, some rows saved, `RUN_SUMMARY` shows the reason.
Likely reason: the archive asked us to slow down or did not answer.
Check: the time of the run and the number of inputs.
Action: run again later, or split a large list into smaller runs. `error` rows are not charged.

#### A very large site has an `error` row with `SOURCE_TIMEOUT`

Symptom: one free `error` row for a site like `reddit.com`, `HTTP 504` in `statusReason`.
Likely reason: the archive could not list millions of captures in time.
Check: `RUN_SUMMARY` shows `SOME_URLS_FAILED`; other URLs are fine.
Action: add `from`/`to`, `collapse: year` or `statusFilter: 2xx`, or use a more exact URL, and run that URL again.

#### A URL has an `error` row with `SOURCE_EXCLUDED`

Symptom: one free `error` row for the URL, the other URLs are listed as usual.
Likely reason: the site asked the archive not to show its captures, or the archive removed them.
Check: open `https://web.archive.org/web/*/<your URL>` in a browser.
Action: none; the archive does not show these captures to anyone. Three such URLs in a row stop the run with `SOURCE_BLOCKED`, because that looks like the archive refusing all requests.

#### Many captures look the same

Symptom: several rows with the same `digest` or the same text.
Likely reason: the archive captured an unchanged page many times.
Action: set **Deduplicate** to "Only when content changed" (`collapse: digest`) to keep only changed content.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### FAQ

#### Do I need a Wayback Machine account or API key?

No. The Actor uses the public Wayback Machine index and archived pages. No login, no key, no cookies.

#### Why do I get fewer captures than I asked for?

`maxSnapshots` is a maximum. The archive may have fewer captures for your filters. `RUN_SUMMARY` shows `moreAvailable: true` when more exist. With `sortOrder: newest`, repeated identical index lines are skipped, so a few rows fewer can come back.

#### How fresh is the data?

Rows show what the Wayback Machine index has at run time. New captures can take hours or days to appear in the index.

#### Is the archived content mine to reuse?

Archived pages belong to their original publishers, and use of the Wayback Machine is subject to the [Internet Archive Terms of Use](https://archive.org/about/terms). You are responsible for how you use the results. This Actor is not affiliated with the Internet Archive.

#### I come from another Wayback Actor. How do the fields map?

`queryUrl` → `inputUrl`, `archiveDate` → `capturedAt`, `archiveUrl` → `snapshotUrl`, `contentLength` → `length`, `contentDigest` → `digest`, `content` → `text`. `statusCode` here is a number or `null`, not a string. A URL with no captures returns a `not_found` row instead of nothing.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Related Actors

- [Bulk URL Status & Redirect Checker](https://apify.com/cliqtomedia/bulk-url-status-redirect-checker) — check which of the archived URLs still work today and where they redirect.
- [XML Sitemap URLs Extractor](https://apify.com/cliqtomedia/xml-sitemap-urls-extractor) — get the current URL list of a site to compare with its archived URLs.
- [Website to Markdown for RAG](https://apify.com/cliqtomedia/website-to-markdown) — get the live text of the same pages to compare with the archived text.
- [SEO Site Audit](https://apify.com/cliqtomedia/seo-site-audit) — audit broken links, meta tags and speed of the live site.
- [Domain WHOIS (RDAP) & DNS Lookup](https://apify.com/cliqtomedia/domain-whois-dns-lookup) — add registration dates and DNS records to the archive history of a domain.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

### Support

For a bug, question or feature request, open an issue on the Actor's **Issues** tab. Include the run ID, your input (without private data) and the error text. Never send tokens or cookies.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/j6rnIDRGfbO6Rjrb0/input)**

# Changelog

This Actor's version history is a separate document: https://apify.com/cliqtomedia/wayback-machine-snapshots/changelog.md

# Actor input Schema

## `urls` (type: `array`):

Up to 100 pages or sites, e.g. apify.com, https://apify.com/pricing. Use apify.com/blog/\* for every page under a path, or \*.apify.com for the whole domain with subdomains. Duplicates (http/https, www) are listed once.

## `matchType` (type: `string`):

exact: only that URL. prefix: every URL starting with it. host: every page on that host. domain: every page on the domain and its subdomains. A \* in the URL (apify.com/blog/\* or \*.apify.com) overrides this for that entry.

## `from` (type: `string`):

Only captures on or after this date (UTC). Formats: 2015, 2015-06, 2015-06-01 or 20150601. Empty: from the first capture.

## `to` (type: `string`):

Only captures on or before this date (UTC), inclusive: 2020 means up to the end of 2020. Same formats as From date. Empty: up to the latest capture.

## `collapse` (type: `string`):

Keep one capture per hour, day, month or year, or skip captures whose content did not change (digest). urlkey keeps one capture per distinct URL, which is handy for listing the pages of a site. none returns every capture.

## `statusFilter` (type: `string`):

Only captures whose archived HTTP status is in this class, e.g. 2xx for successful pages or 3xx for redirects. any keeps all, including revisit records without a status.

## `onlyHtml` (type: `boolean`):

Skip images, scripts, PDFs and other files; keep text/html captures only.

## `mimeTypes` (type: `array`):

Keep only captures of these file types, for example image/, application/pdf or text/html. A value ending in / keeps the whole family (image/ = all images). Up to 20 values. Leave empty for all types; do not combine with HTML pages only.

## `sortOrder` (type: `string`):

oldest: from the first capture forward. newest: the most recent captures first (exact URLs only; prefix and domain matches are listed by URL by the archive).

## `maxSnapshots` (type: `integer`):

Stop after this many captures for each URL or domain. Each saved capture is one paid result. Up to 10,000.

## `includeContent` (type: `boolean`):

Also download each successful HTML or plain-text capture and return its title and visible text. One extra request per capture (slower) and one extra paid event per page with text. At most 300 pages per run (about 2 seconds each).

## `maxContentChars` (type: `integer`):

Cut the extracted text to this many characters per capture; textLength still reports the full length.

## Actor input object example

```json
{
  "urls": [
    "apify.com"
  ],
  "matchType": "exact",
  "collapse": "none",
  "statusFilter": "any",
  "onlyHtml": false,
  "mimeTypes": [
    "application/pdf"
  ],
  "sortOrder": "oldest",
  "maxSnapshots": 20,
  "includeContent": false,
  "maxContentChars": 5000
}
```

# Actor output Schema

## `snapshots` (type: `string`):

One row per Wayback Machine capture.

## `text` (type: `string`):

Captures with archived title and text.

## `runSummary` (type: `string`):

Status, counts per URL, charged events, source attribution and request statistics.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "apify.com"
    ],
    "maxSnapshots": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/wayback-machine-snapshots").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": ["apify.com"],
    "maxSnapshots": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/wayback-machine-snapshots").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "apify.com"
  ],
  "maxSnapshots": 20
}' |
apify call cliqtomedia/wayback-machine-snapshots --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cliqtomedia/wayback-machine-snapshots"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/j6rnIDRGfbO6Rjrb0/builds/T5ye4XrbeVKeVNcBF/openapi.json
