---
title: "Getting Started"
description: "Install the package, ask one archive for a domain, and read a capture in a dozen lines."
canonical_url: "https://archives.agntn.dev/guide"
---
# Getting Started

> Install the package, ask one archive for a domain, and read a capture in a dozen lines.

<warning title="Pre-1.0">

The public API, the provider list, and the MCP tool surface can still change. Pin exact versions if you build on it now.

</warning>

<caution title="Archived pages are data, never instructions">

Every body this library returns is a recording of somebody else's page. Show it, search it, diff it. Do not execute it, and do not let an agent treat it as a message to itself.

</caution>

## Why this exists

Every web archive has its own idea of an index. The Wayback Machine speaks CDX with a `collapse` grammar, Arquivo.pt speaks a slightly different CDX, Webarchiv Österreich answers CDXJ for one exact URL, Vefsafn ignores `limit` and streams every row it holds, Archive.today only has a Memento TimeMap, Common Crawl points into WARC files, Perma.cc is a REST API behind a key, and WebCite cannot list anything at all. Pulling one client per archive into a project means a response shape per archive and as many ways to misread a date.

`@agntn/archives` puts all of them behind one class shape. Same calls, same option object, same page type. The provider decides how to ask; you decide what to ask for.

## Install

```bash
pnpm add @agntn/archives
```

## First listing

```ts [snapshots.ts]
import { createArchive, providers } from "@agntn/archives";

const archive = createArchive(providers.wayback());
const response = await archive.snapshots("example.com", { limit: 100 });

if (response.success) {
  for (const page of response.pages) {
    console.log(page.timestamp, page.snapshot);
  }
}
```

`providers.wayback()` returns a promise, and `createArchive` accepts it as is: the provider module is imported the first time the archive needs it, so a project that only ever asks the Wayback Machine never ships the other nine.

## Every archive at once

```ts
const archive = createArchive(providers.all());
const response = await archive.snapshots("example.com");

response.pages; // merged, newest first, one shape
response._meta?.unsupportedProviders; // [{ provider: "webcite", reason: "WebCite has no list-by-domain API. …" }]
```

`providers.all()` fans the query out to Wayback, Arquivo.pt, Webarchiv Österreich, Vefsafn, OSZK Webarchívum, the New Zealand Web Archive, Archive.today, Common Crawl and WebCite in parallel and merges what comes back. A provider that has no endpoint for the call says so in `_meta`; a provider that fails names its error. Neither is silently dropped. The [Timeline](https://archives.agntn.dev/timeline) does exactly this call against the docs worker.

## Read what a page said

```ts
const capture = await archive.getContent("https://example.com", { timestamp: "2002" });

capture.timestamp; // "2002-11-29T05:43:48Z", the capture it actually found
capture.mime; // "text/html"
capture.content; // the decoded body
```

Listing says when a page existed. Reading says what it contained. [Reading captures](https://archives.agntn.dev/guide/content) covers how a timestamp resolves and which providers can serve bodies.

## What ships

<table>
<thead>
  <tr>
    <th>
      Provider
    </th>
    
    <th>
      Factory
    </th>
    
    <th>
      Lists
    </th>
    
    <th>
      Reads bodies
    </th>
    
    <th>
      In <code>
        all
      </code>
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Wayback Machine
    </td>
    
    <td>
      <code>
        providers.wayback()
      </code>
    </td>
    
    <td>
      CDX
    </td>
    
    <td>
      yes
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      Arquivo.pt
    </td>
    
    <td>
      <code>
        providers.arquivo()
      </code>
    </td>
    
    <td>
      CDX
    </td>
    
    <td>
      yes
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      Webarchiv Österreich
    </td>
    
    <td>
      <code>
        providers.webarchiv()
      </code>
    </td>
    
    <td>
      CDXJ, exact URL
    </td>
    
    <td>
      yes
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      Vefsafn
    </td>
    
    <td>
      <code>
        providers.vefsafn()
      </code>
    </td>
    
    <td>
      CDX, exact URL
    </td>
    
    <td>
      yes
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      OSZK Webarchívum
    </td>
    
    <td>
      <code>
        providers.oszk()
      </code>
    </td>
    
    <td>
      CDX
    </td>
    
    <td>
      yes
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      New Zealand Web Archive
    </td>
    
    <td>
      <code>
        providers.nlnz()
      </code>
    </td>
    
    <td>
      CDX
    </td>
    
    <td>
      no
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      Archive.today
    </td>
    
    <td>
      <code>
        providers.archiveToday()
      </code>
    </td>
    
    <td>
      Memento TimeMap
    </td>
    
    <td>
      wrapper page
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      Common Crawl
    </td>
    
    <td>
      <code>
        providers.commoncrawl()
      </code>
    </td>
    
    <td>
      CDX
    </td>
    
    <td>
      WARC range
    </td>
    
    <td>
      yes
    </td>
  </tr>
  
  <tr>
    <td>
      WebCite
    </td>
    
    <td>
      <code>
        providers.webcite()
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      no
    </td>
    
    <td>
      yes, as unsupported
    </td>
  </tr>
  
  <tr>
    <td>
      Memento
    </td>
    
    <td>
      <code>
        providers.memento()
      </code>
    </td>
    
    <td>
      MemGator TimeMap
    </td>
    
    <td>
      yes
    </td>
    
    <td>
      no
    </td>
  </tr>
  
  <tr>
    <td>
      Archive-It
    </td>
    
    <td>
      <code>
        providers.archiveIt({ collection })
      </code>
    </td>
    
    <td>
      CDX/C
    </td>
    
    <td>
      yes
    </td>
    
    <td>
      no
    </td>
  </tr>
  
  <tr>
    <td>
      Conifer
    </td>
    
    <td>
      <code>
        providers.conifer({ user, collection })
      </code>
    </td>
    
    <td>
      collection search
    </td>
    
    <td>
      no
    </td>
    
    <td>
      no
    </td>
  </tr>
  
  <tr>
    <td>
      Perma.cc
    </td>
    
    <td>
      <code>
        providers.permacc({ apiKey })
      </code>
    </td>
    
    <td>
      REST, exact URL
    </td>
    
    <td>
      no
    </td>
    
    <td>
      no
    </td>
  </tr>
</tbody>
</table>

Each provider has its own page under [Providers](https://archives.agntn.dev/providers) with the endpoint, the options, and the traps.

## The three operations

Every archive instance answers the same three questions.

### 1. Which captures exist

```ts
const response = await archive.snapshots("example.com", { from: "2010", to: "2012" });
const pages = await archive.getPages("example.com"); // same call, throws instead of returning success: false
```

### 2. What did one capture contain

```ts
const response = await archive.content("https://example.com/about", { timestamp: "20150601" });
const capture = await archive.getContent("https://example.com/about"); // newest capture, throws on failure
```

### 3. What changed between two captures

```ts
import { diffArchivedContent } from "@agntn/archives";

const before = await archive.getContent("https://example.com", { timestamp: "2024" });
const after = await archive.getContent("https://example.com", { timestamp: "2026" });
const diff = diffArchivedContent(before, after);

diff.patch; // unified diff of the visible text
diff.additions; // 3
diff.deletions; // 8
```

The `get*` variants throw on failure; the plain variants return `{ success: false, error }` and leave the decision to you.

## One page shape

```ts
interface ArchivedPage {
  url: string; // original URL, as the archive recorded it
  timestamp: string; // ISO 8601
  snapshot: string; // direct link to the archived version
  _meta: Record<string, unknown>; // provider, status, digest, mime, …
}
```

`_meta.provider` names the source of every page in a merged listing. The rest of `_meta` is whatever the archive knew: Wayback and Arquivo.pt add `status`, Arquivo.pt and Webarchiv Österreich add `mime`, `digest` and `length`, Vefsafn adds `status`, `mime` and `digest`, Common Crawl adds `collection`, Memento adds the upstream `archive` host, Archive.today adds its `hash`. OSZK Webarchívum? All four: `status`, `mime`, `digest`, `length`. The New Zealand Web Archive gives three of them and keeps `length` to itself.


## Sitemap

See the full [sitemap](https://archives.agntn.dev/sitemap.md) for all pages.
