# Website History Checker (Wayback Machine) (`watchmere/wayback-website-history`) Actor

Bulk website history from the Internet Archive's Wayback Machine: when each URL or domain was first and last archived, captures per year, distinct versions and last change, every version with links, or what changed between two dates (title, headings, text, links). Official APIs, no key.

- **URL**: https://apify.com/watchmere/wayback-website-history.md
- **Developed by:** [Watchmere .](https://apify.com/watchmere) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 url looked ups

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does Wayback Machine Scraper do?

It looks up a whole list of URLs or domains in the **Internet Archive's Wayback Machine** and tells you their
history, in one clean table:

- **Summary** (one row per URL): when it was **first and last archived**, **how many times**, **captures per year**,
  how many **distinct versions** the page had and **when it last changed**, plus links to the first and last
  archived copy and, if you give a date, the copy closest to that date.
- **Every version** (one row per version): each time the page's content changed, with the date it first appeared,
  how long it stayed the same, its status code and a link to open that version in the Wayback Machine.
- **Compare two dates** (one row per URL): what changed between the archived copies closest to two dates: title,
  meta description, H1/H2 headings, word and link counts, outbound domains, and how much of the text changed (words
  and sentences added and removed, percent changed). The page text itself isn't output.

It uses the Internet Archive's official public APIs (the CDX index and the archived pages themselves), so you don't
need an account or an API key. This Actor isn't made or endorsed by the Internet Archive.

### Who is it for?

- **SEO and domain buyers:** check an expired or for-sale domain before buying it: how old it really is, whether it
  was ever a real site, and what it looked like over the years
- **Investigators, journalists and lawyers:** see when a page existed and what it said around a given date, with
  links to the archived copies
- **Competitor research:** see when a competitor changed its home page, pricing page or messaging
- **Content recovery:** find every archived version of a lost page

### How to use it

1. Paste your **URLs or domains**, one per line (`example.com`, `example.com/pricing` or a full address). A domain on
   its own means its home page; `http`/`https` and `www` count as the same page, as in the Wayback Machine.
2. Pick **What to get**: Summary, Every version, or Compare two dates.
3. Optionally limit the **dates** (a year like `2015`, a month like `2015-06`, or a day like `2015-06-30`).
4. Click **Start** and download the results from the Output tab (CSV, Excel, JSON), or use the **Summary**,
   **Versions** and **Comparison** views.

### Input example

```json
{
  "urls": ["info.cern.ch", "https://example.com/pricing"],
  "mode": "summary",
  "from": "2010",
  "to": "2024",
  "date": "2015-06-30",
  "includeErrors": false
}
```

For a comparison: `"mode": "compare", "compareFrom": "2012", "compareTo": "2024"` (leave both empty to compare the
oldest and newest copies). For every version: `"mode": "captures", "maxCapturesPerUrl": 500`.

### Output examples

These come from the Actor's own test runs (October 2026, shortened).

**Summary** for `info.cern.ch` (the first website):

```json
{
  "url": "info.cern.ch",
  "archived": true,
  "firstSeen": "1997-12-10T18:41:00Z",
  "lastSeen": "2026-10-13T11:15:45Z",
  "totalCaptures": 3587,
  "estimatedCaptures": null,
  "countsExact": true,
  "distinctVersions": 44,
  "capturesPerYear": { "1997": 2, "1998": 4, "1999": 5, "2000": 156, "...": "...", "2025": 345, "2026": 231 },
  "lastChangedAt": "2014-02-08T04:35:18Z",
  "statusCodes": { "200": 3586, "302": 18, "403": 2, "revisit": 1, "501": 1 },
  "closestToDate": { "requested": "2015", "timestamp": "2015-07-02T18:04:30Z", "statusCode": "200",
                     "archiveUrl": "https://web.archive.org/web/20150702180430/info.cern.ch/" },
  "firstArchiveUrl": "https://web.archive.org/web/19971210184100/info.cern.ch/",
  "lastArchiveUrl": "https://web.archive.org/web/20261013111545/info.cern.ch/",
  "note": null,
  "error": null
}
```

**Every version** of `apify.com` from 2015 (first row):

```json
{
  "url": "apify.com",
  "version": 1,
  "timestamp": "2015-02-16T02:12:25Z",
  "lastCapturedAt": "2016-05-12T07:35:54Z",
  "captureCount": 5,
  "statusCode": "200",
  "mimetype": "text/html",
  "digest": "3Z65GIU4US7YSBJ3HD2AU4WJP3YZNWYN",
  "length": 440,
  "archivedUrl": "http://apify.com:80/",
  "archiveUrl": "https://web.archive.org/web/20150216021225/http://apify.com:80/",
  "changed": null
}
```

**Compare two dates** for `apify.com`, 2008 vs 2024:

```json
{
  "url": "apify.com",
  "fromTimestamp": "2008-09-19T04:10:40Z",
  "toTimestamp": "2024-07-03T00:58:23Z",
  "identical": false,
  "titleBefore": "Under Construction",
  "titleAfter": "Apify: Full-stack web scraping and data extraction platform",
  "headingsAdded": ["Build reliable web scrapers. Fast.", "Web scraping can be challenging", "Trusted business partner"],
  "headingsRemoved": ["Under Construction"],
  "wordCountBefore": 102,
  "wordCountAfter": 1515,
  "linkCountBefore": 0,
  "linkCountAfter": 112,
  "outboundDomainsAdded": ["capterra.com", "crawlee.dev", "discord.com", "g2.com", "github.com", "..."],
  "wordsAdded": 1499,
  "wordsRemoved": 86,
  "percentChanged": 98.0,
  "sentencesAdded": 174,
  "sentencesRemoved": 11
}
```

| Field | Meaning |
|---|---|
| firstSeen / lastSeen | First and last capture (UTC) |
| totalCaptures | How many times the page was archived (in your date range) |
| estimatedCaptures / countsExact | For pages archived more than about 120,000 times (the home pages of the biggest sites), the total is estimated from the size of the Archive's index and `countsExact` is `false`; yearly and version counts are then left empty. Example: `google.com` about 12.6 million captures since 11 Nov 1998 |
| distinctVersions | How many times the archived content changed (see the FAQ about dynamic pages) |
| lastChangedAt | When the newest version first appeared |
| statusCodes | Captures per HTTP status (`revisit` = a capture the Archive stored as "same as an earlier one" without saying which status that had) |
| timestamp / lastCapturedAt / captureCount | When a version first appeared, the last capture that still had the same content, and how many captures it covers |
| length | Size of the archived record in bytes (compressed, as stored by the Archive) |
| changed | `true` when this version differs from the page's previous successful version |
| percentChanged | How much of the page's visible text differs between the two copies (0 = same, 100 = completely different) |
| wordsAdded / wordsRemoved / sentencesAdded / sentencesRemoved | How many words and sentences appear only in the newer / only in the older copy |
| note | Anything you should know about this row (never archived, a limit reached) |
| error | Why a lookup failed. Failed lookups are free |

By default only successful captures count (redirects and error pages are left out of every number). Switch on **Count
redirects and errors** to include them.

### Personal data

The Actor outputs page-level facts only, never the text of the pages: comparisons give counts of what changed, not the
changed sentences. The titles, meta descriptions and headings it does output are cleaned first: email addresses and
phone numbers are removed, and people's names are removed on a best-effort basis (a pattern-based filter, so it can
miss a name or remove something that isn't one). Archived pages can contain personal data; you are responsible for
how you use what you open in the Wayback Machine.

### How much does it cost?

You pay per URL, not per row:

- **Summary:** one *URL looked up* per URL. A URL the Archive has never seen counts too, because "never archived" is
  a real answer.
- **Every version:** one *URL looked up* per URL for each started 1,000 versions listed (most pages have fewer, so
  usually one).
- **Compare two dates:** one *comparison* per URL that was compared (it reads two archived pages). If there was
  nothing to compare (never archived, or only one version), it's free.

**Failed lookups are free:** invalid addresses, sites excluded from the Wayback Machine, and lookups that failed
because the Archive didn't answer still appear with an `error`, at no charge. See the **Pricing** tab for the rates.

Set a **maximum cost per run** in the run options and the Actor stops cleanly when it gets there, without starting
lookups it couldn't pay for. If Apify moves a run to another server, the restarted run continues after the last URL
it saved. Versions that were already paid for are kept in the run's storage before they're charged, so the restarted
run saves the rest of them without looking the URL up or charging again.

### Speed and fair use of the Internet Archive

The Internet Archive is a non-profit library, and this Actor is a polite client: at most 2 URLs are looked up at a
time, index searches start at least 2.5 seconds apart (about 24 a minute, following the limits the Archive has given
to other API tools; our test runs measured 24.6–24.9 a minute because a run's first search starts at once), and
archived pages at least 0.25 seconds apart. When the Archive answers "too many requests", every request pauses (1,
then 2, then 5 minutes) and the pace halves; after 4 such answers in a row the run stops and the URLs it didn't reach
aren't charged. A server error is retried twice (after the wait the Archive asks for, if it gives one); if the
Archive fails for 5 URLs in a row, the run stops, since it's probably down, and the URLs it didn't reach aren't charged.

Most pages need one index search; very heavily archived pages need 3–4. In our test runs, 9 URLs (including
google.com, example.com and python.org, which need several searches) took 57–84 seconds: 23 searches, 16.6–24.9 a
minute depending on how fast the Archive answered, and it never asked us to slow down. A comparison needs about 3 searches and 2 page downloads (2 URLs took 18–27
seconds). Plan on roughly 10–20 URLs a minute for summaries and versions, and 4–8 for comparisons.

### FAQ

**Why does a page have almost as many versions as captures?** A new version starts whenever the archived bytes
differ. Many modern pages change a little on every load (tracking codes, timestamps, security tokens), so they count
as a new version at almost every capture; static pages show the real number of edits (info.cern.ch: 44 versions in
3,587 captures). Use **Compare two dates** to see how much the visible text actually changed.

**Why does a page show fewer captures than the Wayback Machine's calendar?** By default redirects and error pages
aren't counted. Switch on *Count redirects and errors* to count every capture.

**Why are some numbers estimated?** The home pages of the biggest sites have been archived millions of times. Reading
millions of index lines would be slow and load the Archive, so for pages above about 120,000 captures the total is
estimated from the size of the Archive's index; the first capture, last capture and last change are still exact.

**Can I get every page of a whole domain?** Not in this version: it looks up exactly the URLs you enter. The
Archive's index refused whole-domain and whole-path searches in all our tests, and the Actor doesn't try to work
around that.

**Why does a site say it's excluded?** Site owners can ask the Internet Archive to exclude their site; its history
then isn't shown to anyone.

**Is this allowed?** The Actor only uses the Internet Archive's public APIs, at a gentle pace, and outputs facts about
pages, not their text or personal data. The Archive's terms of use say access to its collections is for
scholarship and research and that use must stay within copyright law and fair use; check them before reusing
archived material.

**Something isn't working or you'd like a feature?** Open an issue on the Issues tab.

# Actor input Schema

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

One per line: a domain (example.com), a page (example.com/about) or a full address. Each one is looked up in the Internet Archive's Wayback Machine. A domain on its own means its home page. http/https and www are treated as the same page, as in the Wayback Machine.

## `mode` (type: `string`):

Summary: one row per URL with first and last capture, captures per year, number of versions and last change. Every version: one row per distinct version of the page (a new row each time its content changed). Compare two dates: what changed between the archived copies closest to two dates (title, description, headings, text, links).

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

Only count captures from this date on.

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

Only count captures up to the end of this year, month or day.

## `date` (type: `string`):

Optional. Adds the capture closest to this date to each summary row, for example to see what a site looked like on a given day.

## `maxCapturesPerUrl` (type: `integer`):

In 'Every version' mode, at most this many versions are listed per URL, oldest first. Narrow the dates to see later ones.

## `compareFrom` (type: `string`):

The older date, for example 2012. Empty = the oldest archived copy.

## `compareTo` (type: `string`):

The newer date, for example 2024-06. Empty = the newest archived copy.

## `includeErrors` (type: `boolean`):

Off: only real versions of the page (successful captures) are counted and listed. On: captures of redirects (3xx) and error pages (4xx, 5xx) count too.

## `proxyConfiguration` (type: `object`):

Not needed: the Internet Archive's APIs are public. The Actor sends at most 2 requests at a time and slows down when the Archive asks.

## Actor input object example

```json
{
  "urls": [
    "apify.com",
    "https://example.com/"
  ],
  "mode": "summary",
  "maxCapturesPerUrl": 500,
  "includeErrors": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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",
        "https://example.com/"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("watchmere/wayback-website-history").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",
        "https://example.com/",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("watchmere/wayback-website-history").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",
    "https://example.com/"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call watchmere/wayback-website-history --silent --output-dataset

```

## MCP server setup

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

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/QHLrSGbJF7DdetU1o/builds/e4bhEMLa9RCvyXqVU/openapi.json
