Internet Archive API — Search, Metadata & Files avatar

Internet Archive API — Search, Metadata & Files

Pricing

from $0.25 / 1,000 item returneds

Go to Apify Store
Internet Archive API — Search, Metadata & Files

Internet Archive API — Search, Metadata & Files

Search archive.org and get its catalogue as data. One row per item: identifier, title, creators, date, subjects, collections, language, downloads, size and licence. Optional rows per file with direct download URLs, formats, sizes and checksums, and per public review. No API key, no login.

Pricing

from $0.25 / 1,000 item returneds

Rating

0.0

(0)

Developer

Insight Solutions

Insight Solutions

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 hours ago

Last modified

Share

Turn archive.org into a table. Give this Actor a search — collection:librivoxaudio, creator:"Jane Austen" AND mediatype:texts, or just apollo 11 — and get one row per item: identifier, title, creators, date, subjects, collections, language, downloads, size, licence and thumbnail. Pass identifiers instead and you get the full record for each one, plus a row per file with a direct download URL, format, size, MD5 and SHA-1, plus a row per public review.

No API key. No login. No cookies to paste. $0.40 per 1,000 items, proxy included, searches that match nothing are free, and a run that returns nothing costs nothing at all.

Try it in 30 seconds

{
"searchQueries": ["subject:\"machine learning\" AND mediatype:texts"],
"sort": "downloads",
"maxResultsPerQuery": 100
}

Or go straight at items you already know:

{
"identifiers": [
"nasa_techdoc_19930072988",
"https://archive.org/details/0_sense_and_sensibility_librivox"
],
"includeFiles": true,
"fileFormats": ["MP3"],
"includeReviews": true
}

What comes back

One item row per archive.org item:

{
"ok": true,
"rowType": "item", // "item" | "file" | "review" | "diagnostic"
"identifier": "0_sense_and_sensibility_librivox",
"url": "https://archive.org/details/0_sense_and_sensibility_librivox",
"input": "collection:librivoxaudio",
"query": "collection:librivoxaudio", // the query as the index saw it
"position": 1,
"title": "Sense and Sensibility",
"creators": ["Jane Austen"], // always a list, however the Archive stored it
"date": "2007-03-30T00:00:00.000Z", // when the thing itself is dated
"year": 2007, // survives even when the date is only a year
"publicDate": "2007-03-30T06:03:05.000Z",
"addedDate": null, // metadata-API only — see the note below
"mediaType": "audio",
"collections": ["librivoxaudio", "audio_bookspoetry", "…"],
"subjects": ["librivox", "literature", "audiobook", "romance", "England"],
"languages": ["eng"],
"description": "LibriVox recording of Sense and Sensibility, by Jane Austen…",
"descriptionHtml": null, // the uploader's raw markup, metadata-API only
"downloads": 2011009, // all-time, search-index only
"itemSizeBytes": 2173798776,
"filesCount": null, // metadata-API only
"avgRating": 3,
"numReviews": 3,
"license": null, // a licence URL when the uploader declared one
"uploader": null,
"thumbnailUrl": "https://archive.org/services/img/0_sense_and_sensibility_librivox",
"recordSource": "search", // "search" (short record) | "metadata" (full record)
"error": null,
"errorType": null,
"scrapedAt": "2026-09-10T15:04:32.000Z",
"source": "archive.org",
"sourceUrl": "https://archive.org/advancedsearch.php?q=…"
}

One file row per file, with includeFiles: true:

{
"ok": true,
"rowType": "file",
"identifier": "0_sense_and_sensibility_librivox",
"position": 1,
"fileName": "senseandsensibility_01_austen.mp3",
"downloadUrl": "https://archive.org/download/0_sense_and_sensibility_librivox/senseandsensibility_01_austen.mp3",
"format": "VBR MP3", // the Archive's own label, not an extension
"sourceKind": "original", // "original" | "derivative" | "metadata"
"sizeBytes": 9245780,
"md5": "6b8718b186d5cb87178911cd49e4f535",
"sha1": "7158d9c4b8e21acee4a069dde06f20cd84c53064",
"modifiedAt": "2007-03-30T06:00:21.000Z",
"durationSec": 577.86,
"width": null, // the Archive writes 0 on audio; that is not a size
"height": null,
"title": "Chapter 01",
"track": 1 // "1/50" on the wire; the track itself here
}

And one review row per public review, with includeReviews: true:

{
"ok": true,
"rowType": "review",
"identifier": "nasa_techdoc_19930072988",
"reviewer": "Basquetteur",
"reviewerHandle": "@basquette", // archive.org/details/@basquette
"title": "wrong keywords",
"body": "wrong keywords", // exactly as written
"stars": 1,
"reviewedAt": "2017-11-29T20:39:18.000Z"
}

Every row carries every column, with null wherever it does not apply — so a CSV export, a SQL insert or a dataframe gets one stable shape.

Use cases

  • Build a training or RAG corpus from public-domain material. A subject or collection query gives you identifiers, licences and descriptions; includeFiles with fileFormats: ["PDF"] or ["EPUB"] gives you the direct download URL and the checksum for each one. license tells you what you are allowed to do with it before you download a byte.
  • Bulk-download a collection properly. File rows carry md5 and sha1, so a download can be verified rather than assumed, and sourceKind separates the uploader's original from the copies the Archive generated.
  • Catalogue and library work. One row per item with creators, subjects, collections, language, dates and size — the shape a librarian or a metadata pipeline actually wants, out of an API that otherwise answers one item at a time.
  • Media research. mediatype:movies plus dateFrom/dateTo over the Prelinger or NASA collections, sorted by downloads, tells you what survives and what people actually watch.
  • Reception and sentiment. includeReviews gives you the public reviews with star ratings and dates, for items whose reception nobody has ever tabulated.
  • Audit your own uploads. uploader:you@example.com as a query returns everything you have contributed, with sizes, file counts and download totals.

How it works, and why it keeps working

The Internet Archive publishes three JSON endpoints for public use, and this Actor reads exactly those:

StepRequestWhat it gets
1advancedsearch.php?q=…&rows=100&page=1&output=jsonPage one: up to 100 items, plus numFound — how many the query matches
2……&page=2, page=3, …100 more each time, until your cap, your budget, the end of the results, or the index's 10,000 ceiling
Ametadata/<identifier>One item's full record: metadata, every file, and its reviews
Bmetadata/<identifier>/reviewsReviews alone — only when a record does not carry them

Four details in there are the ones cheap scrapers get wrong:

Page numbers, not a cursor. The Archive also publishes a cursor-paged search service, and it is the obvious thing to reach for. In September 2026 we found it handing back page one again for every cursor, and on some queries answering a completely different query's results. Page numbers on advancedsearch.php were correct in the same runs, so that is what this Actor walks: page=1, page=2, and response.start on every page saying where it landed.

Pages can overlap, so identifiers are de-duplicated. Page one of collection:prelinger ends on MilitaryCour and page two opens with it. A large index is not a frozen list; items move while you walk it. Every identifier already returned for a query is skipped the second time, the run log says how many were skipped, and you are never billed twice for the same row.

The same field is a string on one item and a list on the next. creator arrives as an array on 35 of the 50 hits in one captured page and as a bare string on the other 15. subject adds a third shape that only the metadata API uses: "librivox; literature; audiobook; romance; England;" — several subjects packed into one string. All three normalise to a list here, so creators and subjects are always arrays and never a surprise.

File names are paths. 90 of the 103 files on the Apollo 11 onboard film live inside a .thumbs/ directory, so their names contain a /. Percent-encoding the whole name turns that slash into %2F and every download URL into a 404; each segment is encoded on its own.

Underneath: Apify datacenter proxy, one pinned session per parallel worker. The Archive answers a burst from one address with HTTP 429 or 503, and when that happens the session is retired and the same page is asked for once more from a different exit. Retrying on an address that was just refused only deepens it, so it is never done. If the second exit is refused too, the walk stops, keeps every row it already delivered, and files one free blocked row saying where it stopped.

Requests to the same target are spaced 300–600 ms apart and three targets run in parallel. Nothing forces that. The Internet Archive is a non-profit serving these endpoints to anyone who asks, without a key and without a quota, and this is a rate that reads it rather than hammering it.

This is not the Wayback Machine. Archived copies of web pages live in a different index with a different API; paste a web.archive.org/web/… URL here and you get a diagnostic row saying so. That job is Wayback Machine Toolkit.

How it compares

  • No API key, no quota, no login. A search string is the whole input.
  • Search and full records in one Actor. The search index holds a short record; the metadata API holds the complete one. Most tools give you one or the other. Here recordSource tells you which you are looking at, and includeMetadataForSearchHits upgrades search hits when you want the full thing.
  • Files are first-class rows. Direct download URLs, formats, sizes, durations, dimensions, track numbers, MD5 and SHA-1 — as data you can join, not a link you have to scrape a page for.
  • Reviews nobody else returns. Public reviews with star ratings, reviewer accounts and exact dates, usually at no extra request.
  • The messy shapes are handled. String-or-array fields, semicolon-packed subjects, two different timestamp spellings for the same instant, year-only dates, "0" written where a dimension does not exist. Every one of those is a real case from a captured response, and every one is normalised.
  • Failures are free and legible. An unknown identifier, a query that matches nothing, a Wayback URL, a rate-limited page — each produces a diagnostic row with an errorType you can branch on, and no charge. A run that returns nothing at all finishes FAILED with the reason in its status message, never a green run containing an apology.
  • A partial walk is kept, not thrown away. Hit maxRunSecs or your charge ceiling on page 12 and you keep pages 1–11.

Input reference

FieldTypeDefaultWhat it does
searchQueriesarray of stringsprefilled with one queryArchive query syntax: collection:…, creator:"…", subject:"…", uploader:…, plain words, combined with AND / OR / NOT. One item row per hit
identifiersarray of strings[]Item identifiers or archive.org/details/… URLs. Read from the metadata API, so the record is the complete one. Case-sensitive
mediaTypeany | texts | audio | movies | image | software | data | webanyAppended to each query as AND mediatype:…, unless the query already names one
sortrelevance | downloads | date | publicdate | titlerelevanceResult order. A sort the index refuses is dropped once and the query retried, rather than failing
dateFrom, dateToYYYY-MM-DDnoneBound each query by the item's own date. Either end can stand alone
maxResultsPerQueryinteger100Items per query. The walk reads 100-item pages and stops on the page that reaches your number. 0 = everything, up to the index's 10,000 ceiling
includeFilesbooleanfalseOne file row per file on each item in identifiers. Billed as its own event
maxFilesPerIteminteger200Ceiling on file rows per item, applied after fileFormats. 0 = no ceiling
fileFormatsarray of strings[]Keep only these formats. MP3 matches VBR MP3 and 64Kbps MP3; PDF matches Text PDF. Extensions work too
includeReviewsbooleanfalseOne review row per public review on each item in identifiers. Usually costs no extra request
includeMetadataForSearchHitsbooleanfalseFill search hits in from the metadata API. One extra request per hit — a hundred results means a hundred requests
maxConcurrencyinteger3Queries and items in parallel. Each worker keeps its own proxy session. Pages within one query cannot be parallelised
maxRunSecsinteger240Whole-run wall-clock budget. When it runs out the Actor keeps what it has and files a free diagnostic row for each entry it never reached
proxyConfigurationobjectApify datacenterLeave it alone unless you are pulling tens of thousands of items, in which case residential is the upgrade

Output reference

Every row carries the same keys. ok: true is an item, a file or a review; ok: false is a free diagnostic row.

FieldWhat it is
rowTypeitem, file, review or diagnostic
identifier, url, input, query, positionThe item, its public page, the entry you supplied, the query that found it, and where it fell in the order
title, creators, date, year, publicDate, addedDateItem rows: what it is, who made it, when it is dated and when it reached the Archive
mediaType, collections, subjects, languagesItem rows: how the Archive classifies it
description, descriptionHtmlItem rows: the description as text (≤ 5,000 chars) and, from the metadata API, as the uploader wrote it
downloads, itemSizeBytes, filesCount, avgRating, numReviewsItem rows: the five numbers people rank and filter on
license, uploader, thumbnailUrl, recordSourceItem rows: the declared licence URL, who uploaded it, a thumbnail, and whether this row is the short record or the full one
fileName, downloadUrl, format, sourceKind, sizeBytesFile rows: the file, where to get it, what it is, and whether it is the original or a derivative
md5, sha1, modifiedAtFile rows: checksums to verify a download, and when the file was last written
durationSec, width, height, track, titleFile rows: playing time, pixel dimensions, track number and the file's own title
reviewer, reviewerHandle, title, body, stars, reviewedAtReview rows: who, what and when
ok, error, errorTypeWhether this row is data, and if not, why not
scrapedAt, source, sourceUrlWhen, and from exactly which endpoint

errorType on a diagnostic row is one of:

ValueMeaningCharged?
not-foundNo archive.org item with that identifier. Identifiers are case-sensitiveNo
no-resultsThe query is valid and matches nothingNo
invalid-inputThe entry was not usable — a Wayback URL, a non-Archive link, an account page, or a query the index rejected (its own message is in error)No
blockedThe Archive refused our requests from two different exit IPs — usually a rate limit. Rows already returned for that entry are keptNo
timeoutThe run's maxRunSecs budget ran out before this entry was reachedNo
unavailableThe Archive answered with something unusableNo

Pricing

$0.40 per 1,000 items. Pay-per-event, with the proxy already inside that number — there is no separate proxy line on your bill for this Actor.

EventWhat triggers itFREEStarterScaleBusiness
Item returned (primary)One item row written to your dataset$0.0004$0.0004$0.0003$0.00025
File record returnedOne file row — download URL, format, size, checksums$0.0001$0.0001$0.0001$0.0001
Review returnedOne review row$0.0002$0.0002$0.0002$0.0002
Run startedOnce per run, after the first paid row$0.001$0.001$0.001$0.001

Worked example. 50 audiobook identifiers with includeFiles: true and fileFormats: ["MP3"], averaging 100 MP3 derivatives each:

  • 50 items × $0.0004 = $0.02
  • 5,000 file rows × $0.0001 = $0.50
  • 1 run start = $0.001
  • Total: $0.521

What you are never charged for: a query that matches nothing, an unknown identifier, an entry that was not an Archive item, an entry the run never reached before maxRunSecs, or a page the Archive rate-limited. If a whole run comes back empty it finishes FAILED and bills nothing at all, start fee included.

Set ACTOR_MAX_TOTAL_CHARGE_USD on a run and the Actor stops walking once the ceiling is in sight, rather than handing you rows it cannot bill or billing you for rows it cannot hand over. It finishes SUCCEEDED with the ceiling named in its status message, and everything already delivered is yours.

Limits, and the ones that might bite

Search hits carry a shorter record than items. The index does not publish licenseurl, uploader, addeddate or files_count, so those are null on a plain search row — and the metadata API does not publish downloads, so that is null on a plain identifier row. recordSource says which record you have. includeMetadataForSearchHits: true merges both, at one extra request per hit.

10,000 results per query is the index's ceiling, not ours. advancedsearch.php refuses to page past result 10,000 — page × rows may not go beyond it — so a walk stops there whatever maxResultsPerQuery says, and the run log says it stopped. Split a bigger job by date range, by collection or by media type; collection:prelinger AND date:[1950-01-01 TO 1959-12-31] is 1,567 items where the collection is 10,468.

includeFiles on a large item is a lot of rows. A 50-chapter LibriVox audiobook has 377 files, because the Archive derives an MP3, an Ogg, a spectrogram and two analysis files for every chapter. That is why maxFilesPerItem defaults to 200 and why fileFormats exists.

Files and reviews follow identifiers, not search hits. A search returns item rows. To get the files or reviews for what a search found, run the search first and feed the identifiers back in — deliberately, so a hundred-result search cannot quietly turn into thirty thousand file rows.

Dates on the Archive are what uploaders typed. Plenty of items are dated by year alone, some are wrong, and a few are missing. date is null when the value is not a full calendar date and year carries what is known; nothing here invents the first of January.

A licence of null is not permission. Most Archive items carry no declared licence, and the Archive hosts material under many different rights situations. license reports what the uploader declared and nothing more; what you may do with a file is your call to make.

Star ratings are sparse. Most items have no reviews at all, and avgRating on a search hit comes from the index while on an identifier it is averaged from that item's own rated reviews. Reviews left without a rating are not counted as zero stars.

The Archive may change the format. These are public, undocumented JSON endpoints and they can change without notice — that is true of every tool that reads archive.org, including the ones that do not say so. When a shape changes, rows stop arriving and you get free blocked or unavailable diagnostic rows rather than quietly wrong data, and a run that returns nothing bills nothing.

Rate and reliability. Requests go out through Apify datacenter proxy with per-worker sessions, one rotation per refusal, and a 300–600 ms pause between requests to the same target. Three in parallel is the default because the Archive is a free public service and this is a rate that respects it; raising maxConcurrency speeds a long list up and makes 429s more likely.

Use it from an AI agent, or from code

One JSON object in, one flat array out — the shape agent runtimes want. The Actor runs with limited permissions, uses pay-per-event pricing and never enters Standby, so it works over the Apify MCP server and with x402 agentic payments. The Integrations tab pushes results to Slack, a webhook, Zapier, Make, Google Sheets, Snowflake or BigQuery.

curl -X POST "https://api.apify.com/v2/acts/insight.solutions~internet-archive-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchQueries":["collection:librivoxaudio"],"sort":"downloads","maxResultsPerQuery":100}'
# pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("insight.solutions/internet-archive-api").call(run_input={
"identifiers": ["0_sense_and_sensibility_librivox"],
"includeFiles": True,
"fileFormats": ["MP3"],
"includeReviews": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if not row.get("ok"):
print("skipped:", row["input"], row["errorType"])
elif row["rowType"] == "item":
print(f'{row["title"]}{row["mediaType"]}, {row["filesCount"]} files')
elif row["rowType"] == "file":
print(f' {row["fileName"]} {row["sizeBytes"]} bytes {row["md5"]}')
else:
print(f' {row["stars"]}{row["reviewer"]}: {row["title"]}')

FAQ

What query syntax does it take? The Archive's own. Field searches (collection:, creator:, subject:, title:, description:, uploader:, mediatype:, date:, identifier:) combined with AND, OR, NOT and parentheses, plus plain words for a full-text search. Quote anything containing a space.

How many items can I get from one query? Up to 10,000 — the search index's own ceiling for one result set. Set maxResultsPerQuery: 0 for all of them, and split bigger jobs by date range or collection.

Can I download the actual files? This Actor returns the direct download URL, the format, the size and the checksums for every file. Fetching the bytes is a separate job and a different bill — but everything you need to do it correctly, verification included, is in the row.

Does it read the Wayback Machine? No. Archived web pages are a different index. Use Wayback Machine Toolkit for those.

Why is downloads empty on some rows? Because that row came from the metadata API, which does not publish a download count — only the search index does. recordSource tells you which record a row is.

Are file and review rows charged separately? Yes: $0.0001 per file row and $0.0002 per review row, against $0.0004 per item. Leave includeFiles and includeReviews off and neither is fetched or billed.

What happens if one query fails? The others still run. The failed one produces a free diagnostic row and the run finishes SUCCEEDED. If every entry fails, the run finishes FAILED and you are billed nothing at all.

Is the data fresh? Live. Every run reads archive.org at that moment; nothing is cached.

  • Public endpoints only. Every source is a public Internet Archive API. The Actor never logs in, never accepts cookies or session tokens, never takes an API key belonging to anyone else, and never touches private items, accounts or borrowing records.
  • Rights vary item by item. The Archive hosts public-domain works, openly licensed works, and works held under many other arrangements. license reports the licence URL the uploader declared, and a null there means nothing was declared — not that the item is free to reuse. Checking the rights on what you download is your responsibility.
  • Reviews and uploader names are personal data in most jurisdictions. A review carries a public account name and a date, and under the GDPR and similar laws that is personal data about an identifiable person. You are the controller of whatever you collect: have a lawful basis, keep only what you need, honour deletion requests, and remember that a review deleted on archive.org stays in your dataset until you remove it.
  • Be a good citizen. The Internet Archive is a non-profit that serves these endpoints to everyone, free, without a key. The defaults here — three targets in parallel, a pause between requests, a hard ceiling on results per query — are set to read it politely, and raising them is a decision to take seriously. Consider donating.
  • Not affiliated with the Internet Archive. All names and trademarks belong to their respective owners and are used only to describe which public endpoints this Actor reads.

Our other Actors

Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.

Video, audio & social

News, documents & the web

Business, finance & jobs

Apps & games