Recover pdf from dead website

Find and recover PDFs from dead websites using the Wayback Machine CDX API. Includes Office docs, images, and other file types.

Why PDFs Are Harder to Recover Than HTML Pages

Most Wayback Machine tutorials focus on HTML pages because that is the default capture type: the crawler fetches a page, follows its links, and repeats. A PDF is just a file, so it only gets archived if a crawler happened to encounter the link to it. That single difference explains most of the frustration people have with recovering documents.

There is a second, more technical difference. Recovering an HTML page means saving a file full of readable text, and a partial capture is still mostly useful. Recovering a PDF means saving an opaque binary file, where a truncated download is not a partial document, it is a broken one. The archive can hold a record for a capture whose body is empty or incomplete, so the download step needs verification rather than trust.

On the positive side, PDFs that were ever linked from a public page have a good archive hit rate, because crawlers follow links as routinely as humans do. Standalone PDF URLs, ones that were never linked from anywhere public, are rarely captured. Knowing which category you are in tells you whether to keep searching or to change tactics entirely.

If you need more background on the archive itself, start with our guide to using the Wayback Machine to restore websites before you go hunting for a specific document.

Use the Wayback Machine CDX API for PDFs

The CDX API is the index of everything the archive holds for a given URL pattern, and it accepts a filter parameter to restrict results to one MIME type. A MIME type is the label browsers use to describe a file format, such as application/pdf or image/jpeg. To find every archived PDF on a domain:

curl 'https://web.archive.org/cdx/search/cdx?url=example.com/*&output=json&filter=mimetype:application/pdf&limit=10000'

The response is a JSON array whose first element is a header row of field names. Each row after it is one capture, with timestamp, original, mimetype, statuscode, digest, and length in that order. Because the filter already guarantees PDFs, every mimetype value will read application/pdf.

Two fields earn their keep here. The digest is a content hash, so rows sharing a digest are byte-for-byte identical captures and you only need to download one of them. The length is the stored record size, which is your fastest indication that a capture is empty or truncated. Add filter=statuscode:200 if you want to skip captures that only archived an error page, and collapse=digest to get the deduplicated list directly.

For the parameter-by-parameter explanation of CDX, see our Wayback Machine API tutorial for developers.

Alternative: Google Scholar + Library Archives

For academic PDFs, Google Scholar is worth trying before concluding a paper is gone. Under some results it shows a link to cached copies hosted elsewhere, surfaced through the “All versions” entry. This is not guaranteed and the copy is not always the publisher’s version of record, so treat it as a lead to check rather than the authoritative file.

For published papers and books, check the Internet Archive’s texts collection and your nearest university library archive. These libraries often hold legitimate preservation copies that pre-date any site deletion, and a librarian can often locate a paywalled paper the web no longer serves.

Where the Wayback Machine comes up short, it is also worth knowing what else is out there. Our top 5 Wayback Machine alternatives in 2025 compares capture coverage and rules across the other archiving services, and several of them index files that the Internet Archive never crawled.

Recover Office Docs, Images, Videos

The same CDX approach works for any file type, because the filter value is just a MIME type. Common ones:

  • application/pdf — PDF documents
  • application/msword — legacy Word .doc
  • application/vnd.openxmlformats-officedocument.wordprocessingml.document — Word .docx
  • application/vnd.ms-excel — legacy Excel .xls
  • image/jpeg, image/png — images
  • video/mp4 — video

To see what a domain actually archived before guessing at filters, drop the filter parameter entirely and inspect the mimetype field in the output. That gives you a quick inventory of what kinds of files the archive holds, and tells you which of them are worth chasing.

Note that older MIME types and newer ones describe the same format, so a site that switched from application/msword to application/vnd.openxmlformats-officedocument.wordprocessingml.document will need both filters to find everything. If a document is genuinely missing after a targeted search, the broader context in our step-by-step restoration guide covers the other places recovery copies tend to hide.

Step-by-Step: Bulk Download with Python

This script queries the CDX index for every archived PDF on a domain, deduplicates by content hash, downloads each distinct file, and prints a result line per file. It uses only the Python 3 standard library, so there is nothing to install.

import json
import os
import time
import urllib.parse
import urllib.request

UA = "pdf-recovery/1.0 (contact: https://example.com/contact)"
DELAY = 1.5
OUT = "recovered_pdfs"


def list_pdfs(domain):
    query = urllib.parse.urlencode({
        "url": domain + "/*",
        "output": "json",
        "fl": "timestamp,original,statuscode,mimetype,digest,length",
        "filter": ["mimetype:application/pdf", "statuscode:200"],
        "collapse": "digest",
    })
    target = "https://web.archive.org/cdx/search/cdx?" + query
    request = urllib.request.Request(target, headers={"User-Agent": UA})
    with urllib.request.urlopen(request, timeout=60) as response:
        payload = json.loads(response.read().decode("utf-8", "replace"))
    header = payload[0] if payload else []
    return [dict(zip(header, row)) for row in payload[1:] if isinstance(row, list)]


def snapshot_url(timestamp, original):
    return "https://web.archive.org/web/" + timestamp + "id_/" + original.lstrip("/")


def safe_name(original):
    tail = original.split("?")[0].rstrip("/").split("/")[-1] or "document.pdf"
    return urllib.parse.quote(tail, safe="._-()")


os.makedirs(OUT, exist_ok=True)
for row in list_pdfs("example.com"):
    path = os.path.join(OUT, safe_name(row["original"]))
    if os.path.exists(path) and os.path.getsize(path) > 0:
        print("skip", path)
        continue
    request = urllib.request.Request(snapshot_url(row["timestamp"], row["original"]),
                                     headers={"User-Agent": UA})
    try:
        with urllib.request.urlopen(request, timeout=60) as response:
            data = response.read()
        if not data:
            print("empty body, archived as zero bytes:", row["original"])
            continue
        with open(path, "wb") as handle:
            handle.write(data)
        print("saved", path, len(data), "bytes")
    except Exception as exc:
        print("failed", row["original"], exc)
    time.sleep(DELAY)

Three things in that script are doing quiet work. The id_ marker in the snapshot URL asks the archive to serve the stored bytes without rewriting links, so you get a file that behaves like the original rather than one wrapped in archive tooling. The collapse=digest parameter means a PDF re-captured unchanged fifty times costs you one download. And the zero-length check matters: the archive sometimes holds a record for a capture whose payload did not come back intact, and an empty file is worse than no file at all, so the script reports it and moves on.

Common Errors (429, missing snapshots)

Error 429 means you are being rate-limited. Increase the delay between requests, register for an API key if this is ongoing work, or pause and resume later. The exact anonymous limit is not published as a fixed number, so treat any specific figure as a rough starting point rather than a quota. Our full Wayback Machine 429 error guide covers backoff strategies and the retry logic worth building in.

Missing snapshots have three likely causes. The PDF may never have been linked from a public page, in which case no crawler knew it existed. The site’s robots.txt may have excluded the directory, in which case the archive honoured that and stored nothing. Or the file may have moved during a site migration, leaving the old URL orphaned with a captured index page and nothing behind it. In the last case, querying the new domain is often more productive than retrying the old one.

If a PDF is genuinely not in the archive, archive.ph and similar services are worth a try, though their search interface rather than a documented API is usually the practical route. If the document matters enough to justify a manual hunt, our document recovery service takes on exactly these cases.

FAQ: PDF Recovery

Can I recover a PDF that was never linked anywhere?

Almost certainly not from a public archive. Without an inbound link, no crawler ever discovered the URL, so there was nothing to capture and no record to return. The realistic options are all on your side of the internet: your own browser history, the machine that originally downloaded it, any cloud drive or email attachment it passed through, and the person or team who has it and simply lost track. The exception is a file whose name is predictable, because some archives do store unlinked documents that were submitted or captured directly.

How long does Wayback keep PDFs?

The Wayback Machine does not deliberately expire stored snapshots, so a PDF that was captured is generally still there years later. The exceptions are cases where a capture was removed on request, whether from a copyright complaint, a privacy request, or a webmaster asking for their material to be taken down. That is why a URL that returned a snapshot last year can return nothing today, and why an old printed record or saved CDX query of a successful capture is genuinely worth keeping as evidence.

What if the PDF I recovered is corrupted?

Start by checking the byte size against the length field in the CDX output. A file far smaller than the archived record size was truncated in transfer and should be fetched again. If the size matches but the file still will not open, try a different capture timestamp, since re-captures sometimes differ. Finally, try the if_ marker instead of id_, which serves the file framed rather than bare, and can bypass quirks in how your browser or PDF reader handles the raw response.