# Wayback Snapshot Offline Export (`automation-lab/wayback-snapshot-offline-export`) Actor

Export supplied Wayback snapshots into selector-scoped text, image and provenance JSON plus sanitized offline HTML with bounded embedded images. No subpage crawling or interactive cloning.

- **URL**: https://apify.com/automation-lab/wayback-snapshot-offline-export.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.13 / 1,000 item extracteds

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

## Wayback Snapshot Offline Export

Turn a supplied list of archived replay URLs into **Wayback snapshot export** records and clean offline page artifacts. Get selector-scoped text, image metadata, capture provenance and parallel JSON, plus sanitized standalone HTML with bounded embedded raster images.

This is a content-preservation tool, not a site restorer. It does not search for captures, crawl subpages, preserve interactive applications, or produce pixel-perfect copies.

### Who is it for?

- Researchers building a corpus from known archived URLs.
- Journalists retaining readable copies of historical public pages.
- Content teams extracting selected article text and image descriptions.
- Archive analysts who need requested-versus-resolved capture provenance.

### Why use this Actor?

A capture-history list does not contain the captured page. A generic source downloader can retain scripts and network dependencies. This Actor instead pairs selected content records with neutralized HTML that can be opened without fetching a live website.

Every image omission is explicit. Archive redirects are retained in provenance rather than presented as exact requested captures. All network fetches remain on web.archive.org; missing archived assets are never replaced with present-day versions.

### Getting started

1. Copy an HTTPS Wayback replay URL containing a full 14-digit timestamp.
2. Add it to **Archived snapshot URLs**.
3. Set the maximum number of supplied snapshots to attempt.
4. Optionally select text, images and metadata separately using CSS selectors.
5. Run the Actor and inspect the dataset plus **Offline HTML and JSON files**.
6. Download the corresponding `.html` record from the run's key-value store and open it locally.

The built-in input exports the archived W3C homepage, verified with embedded images. For a minimal text-only control, try this Example Domain sample:

```json
{
  "startUrls": [
    {"url": "https://web.archive.org/web/20200101000000/http://example.com/"}
  ],
  "maxItems": 1
}
```

The Archive can redirect that timestamp to an available neighboring capture. Both timestamps appear in the output.

### Wayback snapshot export inputs

| Input | Meaning |
|---|---|
| `startUrls` | 1–10000 supplied HTTPS archived replay URLs, each with a 14-digit capture timestamp. Strings or `{url}` objects. |
| `maxItems` | Maximum unique supplied captures attempted globally in input order; default 10, range 1–10000. |
| `textSelector` | CSS selector whose text is combined; default `body`. Empty matches fail the capture. |
| `imageSelector` | CSS selector selecting `img` elements directly; default `img`. |
| `metadataSelector` | Containers or title/meta elements to inspect; default `head`. |
| `maxImages` | Distinct asset fetch attempts per capture, including failures; default 20, range 0–100. |
| `maxAssetBytes` | Per-image byte ceiling; default 1048576, maximum 2097152. |
| `maxTotalAssetBytes` | Aggregate downloaded validated raster bytes per capture before base64, including output-budget omissions; default 8388608, maximum 16777216. |

Normalized duplicate replay URLs are skipped. Zero images disables asset downloads; zero snapshots is invalid. No input is unlimited. URL-list files, original live URLs and wildcard capture searches are not supported.

Selectors affect the JSON fields independently. They do **not** crop the offline HTML. For example, use `article` for text and `article img` for images while keeping `head` for metadata.

### Extracted fields

| Field | Meaning |
|---|---|
| `requestedReplayUrl`, `requestedTimestamp` | Normalized requested raw replay and timestamp. |
| `replayUrl`, `timestamp`, `originalUrl` | Actual resolved capture and original page identity. |
| `title` | Title in the metadata scope; null if absent. |
| `text` | Whitespace-normalized selected text, without scripts, style text or Archive toolbar. |
| `metadata` | Named/property/http-equiv meta entries within the selection. |
| `images` | Original/requested/resolved asset URLs, alt/title, detected MIME, byte count and omission/reuse reason. |
| `assetBytes`, `assetRequests` | Downloaded validated raster bytes (including output-budget omissions) and asset fetch attempts, excluding internal retries and redirects. |
| `sourceSha256` | Hash of downloaded archived page bytes. |
| `status` | `complete` or `partial_assets` for selected image embedding, not a fidelity guarantee. |
| `htmlKey`, `jsonKey` | File keys in this run's default key-value store. |
| `htmlBytes`, `exportedAt` | Offline HTML size and export timestamp. |

Capture dates are Archive timestamps; publication dates only appear when the page provides them in selected metadata. No inferred publication date is fabricated.

### Example output

A locally verified Example Domain export resolved the requested 2020 timestamp to `20191231234501`:

```json
{
  "requestedTimestamp": "20200101000000",
  "timestamp": "20191231234501",
  "originalUrl": "http://example.com/",
  "title": "Example Domain",
  "text": "Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. More information...",
  "images": [],
  "assetBytes": 0,
  "status": "complete",
  "htmlKey": "snapshot-<stable-hash>.html",
  "jsonKey": "snapshot-<stable-hash>.json"
}
```

The actual dataset includes all documented fields. The parallel JSON file mirrors its record. The export summary records counts and capture failures; only successful snapshot records produce an item event.

### Offline HTML and images

HTML is converted to a readable content-first document with built-in neutral styling. Scripts, forms, frames, embedded objects, original CSS, remote links, event handlers and network dependencies are removed. A restrictive content-security policy blocks remote loads.

Selected PNG, JPEG, GIF and WebP images are embedded as data URLs after signature checking. SVG, background images, fonts, audio, video and `srcset` variants are not preserved. Image links and navigation are disabled. Source alt text remains where available.

Existing absolute or Archive-relative replay image URLs retain their requested capture identity. Original relative URLs use the first valid document base, or the resolved original page URL; every fetch remains archived. HTML encoding is sniffed from BOM, HTTP charset and early meta declarations (including Windows-1252), then exported as UTF-8. Undecodable replacement text fails the capture rather than becoming a charged preservation result.

Archived assets may resolve to a different timestamp from their containing page. Check each asset's resolved replay URL. Reused embedded assets have zero additional bytes and a reuse explanation.

A `partial_assets` record is useful text plus offline HTML with explicit omitted images. `complete` only means all selected images were embedded. It never means a full interactive or visual clone.

### Limits and failure behavior

- Source HTML and decoded text are capped at 2 MiB, with at most 10000 less-than characters admitted before DOM parsing. Excess complexity fails the capture. Processing is sequential.
- Serialized image data URLs are capped at **4 MiB across every occurrence**, including duplicates. Excess images are omitted with a reason; useful text remains. Download budgets alone do not determine embedding capacity.
- Final UTF-8 HTML is capped at 16 MiB; overflow fails the capture with no result charge. The chosen 512 MiB allocation is measured with maximum-size local fixtures and SDK storage overhead.
- Asset limits apply independently per snapshot; the tighter count/per-image/total/serialized bound wins.
- Each request has a 30-second timeout, up to three transient attempts, and at most five checked archive redirects.
- No proxies, browser or residential fallback is enabled.
- Unsupported HTML responses, absent text, missing captures and exhausted fetches are errors, not empty success rows.
- Successful exports are retained when another supplied capture fails; the run then fails with partial results. Inspect `EXPORT_SUMMARY` before treating a batch as complete.
- Runtime, platform billing limits and upstream availability can stop a large batch. Split very large lists into manageable batches.

### How much does it cost to export Wayback snapshots?

The configured pay-per-event model has one `start` fee and one `item` event per successfully exported snapshot. Images and HTML/JSON files have no separate event charge. Duplicate or failed captures produce no item charge; the run-start event still applies once work begins.

The start fee is **$0.001 per run**. Snapshot item prices follow your qualifying aggregate monthly Apify Store spend tier, not volume in this Actor alone:

| Tier | Per exported snapshot |
|---|---:|
| FREE | $0.0040818 |
| BRONZE | $0.0035494 |
| SILVER | $0.0027685 |
| GOLD | $0.0021296 |
| PLATINUM | $0.0021296 |
| DIAMOND | $0.0021296 |

At BRONZE, estimated charges including the start fee are $0.0045494 for one successful snapshot, $0.036494 for 10, and $0.35594 for 100. At FREE, 10 successful snapshots are approximately $0.041818. These estimates assume one run and the stated successful count; platform billing controls and applicable taxes can affect the final invoice. Consult Apify's active pricing panel before starting.

### Integrations

Use the dataset JSON with Python, notebooks or a data warehouse for archive-text analysis. Use `htmlKey` and `jsonKey` with the same run's key-value store to retrieve corresponding artifacts. Keep files in object storage or a document-management system outside an LLM's context.

Feed known replay URLs from an archival inventory workflow. This Actor deliberately does not discover captures or subpages. A recurring external workflow can rerun a supplied list, but the Actor itself does not track changes, schedule runs or alert on new snapshots.

### API usage

Replace `YOUR_TOKEN` with an authorized Apify token; keep it private.

```bash
curl -X POST \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  'https://api.apify.com/v2/acts/automation-lab~wayback-snapshot-offline-export/runs' \
  -d '{"startUrls":[{"url":"https://web.archive.org/web/20200101000000/http://example.com/"}],"maxItems":1}'
```

JavaScript using `apify-client`:

```javascript
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/wayback-snapshot-offline-export').call({
  startUrls: [{url: 'https://web.archive.org/web/20200101000000/http://example.com/'}],
  maxItems: 1
});
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 10 });
```

Python using `apify-client`:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/wayback-snapshot-offline-export').call(run_input={
    'startUrls': [{'url': 'https://web.archive.org/web/20200101000000/http://example.com/'}],
    'maxItems': 1,
})
items = client.dataset(run['defaultDatasetId']).list_items(limit=10).items
```

Use the run's default key-value store record endpoint to download the matching files. Run/storage identifiers are metadata, not content.

### MCP usage

Configure an Actor-scoped endpoint:

```bash
claude mcp add --transport http apify \
  'https://mcp.apify.com?tools=automation-lab/wayback-snapshot-offline-export'
```

Claude Desktop, Cursor, and VS Code configuration:

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/wayback-snapshot-offline-export"}}}
```

Example prompt: “Export this supplied Wayback capture, selecting article text and article images. Show the capture provenance and artifact keys; do not clone interactive behavior.”

Discover actual names and argument schemas with scoped `tools/list`. Actor selection also exposes run, dataset, key-value record and abort helpers; discovery is not execution permission. After an authorized invocation, retain the returned run ID and follow that same run. If pending, poll with bounded 2/4/8-second backoff capped at 10 seconds and a 120-second total deadline. On timeout, recover the known run instead of starting again; report pending at the deadline.

After success, read untransformed dataset pages of 20 rows, at most 100 rows and 64 KiB of serialized UTF-8 result content admitted to model context, whichever is reached first. Enforce byte ceilings host-side; summarize oversized rows with disclosure. Track source offsets and report truncation/continuation. If your client cannot intercept oversized results, do not claim a hard byte guarantee. Keep full exports in storage. Client caching/discovery does not guarantee token savings.

### Legality and diagnostics

Only process archived content you are authorized to use. Public availability does not grant redistribution rights. Respect source licensing, privacy, Internet Archive policies and relevant law; do not use the Actor to recover or distribute private or unlawfully obtained material. This tool is unofficial and unaffiliated with the Internet Archive.

No AI model processes page content. Data is processed ephemerally in memory, with exported records stored in your run's Apify dataset/key-value store until your platform retention/deletion settings remove them; no Actor-global cache or retained session is created. You can delete those stores through Apify. Report problems using the Actor's Apify Issues tab.

Failed operations send sanitized diagnostic input, exceptions and Actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL query strings are removed, and reports are retained for 30 days.

### FAQ and troubleshooting

**Why is the timestamp different?** The Archive can redirect to a neighboring available capture. Requested and resolved capture timestamps are both preserved.

**Why are images missing?** Inspect `images[].reason`: byte/count limits, unsupported formats or missing archived assets can cause omissions. Increase safe bounds if appropriate, or select fewer relevant images.

**Why did my selector fail?** Selectors operate on archived static HTML, not a live browser DOM. Test against the actual archived content; empty selected text fails the snapshot.

**Can I discover subpages or use a date window?** No. Supply exact archived replay URLs. This bounded product excludes capture discovery and site crawling.

**Does offline mean the original page works exactly?** No. It is sanitized static content, not a functional application or pixel-perfect restoration.

### Related Actors

[Wayback Machine Snapshot History Scraper](https://apify.com/automation-lab/wayback-machine-snapshot-history-scraper) serves the separate capture-history inventory workflow. Use its timestamped replay URLs as supplied inputs here. This Actor adds page-content extraction and safe offline artifacts, not another CDX history list.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/wayback-snapshot-offline-export/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

HTTPS web.archive.org/web/ URLs with a full 14-digit capture timestamp and an HTTP(S) original URL. Replay modifiers are normalized to raw id\_ requests. Redirected capture timestamps are recorded. Duplicate normalized URLs are skipped; all URLs are validated even beyond the item limit. No live pages or URL-list files.

## `maxItems` (type: `integer`):

Global maximum unique supplied snapshots attempted, in input order; default 10. Range 1–10000, no unlimited setting. Failed captures produce no charged result and fail the run after retaining successful partial exports.

## `textSelector` (type: `string`):

CSS selector for text extraction, default body. Matching trees are traversed once even when selectors overlap, with normalized whitespace; scripts, archive toolbar and style text are excluded. Empty matches fail that snapshot. Does not limit the offline HTML content.

## `imageSelector` (type: `string`):

CSS selector selecting img elements directly (for example article img); default img. Only selected src images are fetched and included in image metadata, subject to asset bounds. Other images, srcset, background images and remote resources are removed from offline HTML.

## `metadataSelector` (type: `string`):

CSS selector for metadata containers or title/meta elements directly, default head. Captures title and named/property/http-equiv meta entries inside the selection. Missing values remain null/empty; capture provenance is always recorded independently.

## `maxImages` (type: `integer`):

Maximum distinct image fetches attempted per snapshot, including failures. Default 20, range 0–100. Zero disables image fetching. Duplicate successfully embedded images share bytes; omissions are recorded.

## `maxAssetBytes` (type: `integer`):

Maximum downloaded bytes per raster image (PNG/JPEG/GIF/WebP). Default 1048576; range 1024–2097152. Larger or unsupported assets are omitted, not linked remotely.

## `maxTotalAssetBytes` (type: `integer`):

Maximum aggregate downloaded validated raster bytes per snapshot, including assets omitted by the output budget. Default 8388608; range 1024–16777216. Independently, serialized data URLs are capped at 4 MiB across all occurrences, including duplicates; excess images are explicitly omitted. Source HTML and decoded text are capped at 2 MiB, markup at 10000 less-than characters, and final offline HTML at 16 MiB; complexity/decoding failures produce no charged result.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://web.archive.org/web/20200101000000/https://www.w3.org/"
    }
  ],
  "maxItems": 10,
  "textSelector": "body",
  "imageSelector": "img",
  "metadataSelector": "head",
  "maxImages": 20,
  "maxAssetBytes": 1048576,
  "maxTotalAssetBytes": 8388608
}
```

# Actor output Schema

## `dataset` (type: `string`):

Text, image metadata and capture provenance.

## `files` (type: `string`):

Run-scoped artifact keys; download a snapshot HTML file for offline use.

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

Counts and failed capture details.

# 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 = {
    "startUrls": [
        {
            "url": "https://web.archive.org/web/20200101000000/https://www.w3.org/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/wayback-snapshot-offline-export").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 = { "startUrls": [{ "url": "https://web.archive.org/web/20200101000000/https://www.w3.org/" }] }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/wayback-snapshot-offline-export").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 '{
  "startUrls": [
    {
      "url": "https://web.archive.org/web/20200101000000/https://www.w3.org/"
    }
  ]
}' |
apify call automation-lab/wayback-snapshot-offline-export --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/wayback-snapshot-offline-export"
        }
    }
}
```

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/fVTM4ZOStFgNkuQPv/builds/ISqR3MLQNjb42Oq9z/openapi.json
