Link Rot Checker: Dead Links with Closest Archived Copy
Pricing
from $0.60 / 1,000 link checkeds
Link Rot Checker: Dead Links with Closest Archived Copy
Broken link checker for a list of URLs. One row per link: alive, redirected or dead, the HTTP status, the full redirect chain and, for every dead link, the newest working copy in the Wayback Machine to replace it with. Blocked and unreachable links are never charged.
Pricing
from $0.60 / 1,000 link checkeds
Rating
0.0
(0)
Developer
Adriana Voss
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
Paste a list of URLs and get one row per link: alive, redirected or dead, the HTTP status, the full redirect chain, and for every dead link the newest copy the Wayback Machine saved while the page still worked, ready to use as the replacement. A broken link checker that also hands you the fix. No API key, no account, no proxy.
Who it's for
- Content and SEO teams cleaning outbound links in a blog, a docs site or a knowledge base, who need the dead ones and something to point them at instead.
- Researchers, librarians and editors checking the references of a paper, a report or a wiki article for link rot, and swapping in an archived address where the source is gone.
- Newsletter and course authors checking every link before a send or a relaunch.
- Developers and agencies auditing the links of a site they inherited, straight from a sitemap or a database export.
What you get
One flat row per link:
| What | Columns |
|---|---|
| The verdict | sourceUrl, linkStatus, isBroken, statusCode, reason |
| Where it goes now | finalUrl, redirectKind, redirectCount, redirectChain |
| The replacement | archiveStatus, archivedUrl, archivedAt |
| Details | blockedBy, contentType, responseTimeMs, scrapedAt |
Three example rows, shortened. They are the three pre-filled links, read on 2026-10-11:
| sourceUrl | linkStatus | statusCode | reason | archiveStatus | archivedUrl | archivedAt |
|---|---|---|---|---|---|---|
| https://example.com/ | alive | 200 | OK | NOT_CHECKED | ||
| https://example.com/this-page-does-not-exist | dead | 404 | HTTP_404 | NONE | ||
| https://www.google.com/reader/about/ | dead | 404 | HTTP_404 | FOUND | https://web.archive.org/web/20210503140021/https://www.google.com/reader/about/ | 2021-05-03T14:00:21Z |
What each status means
linkStatus | Meaning | Charged |
|---|---|---|
alive | Answers normally at the address you gave. | yes |
redirected | Works, but at another address. redirectKind says how far it moved. | yes |
dead | 404, 410, another error status, a domain that no longer exists, a refused connection or an invalid certificate. | yes |
blocked | The site refused the check (403, 429, a login wall, a bot-protection page). The page is probably fine in a browser, so it is not called dead. | no |
unreachable | No answer after two attempts. It cannot be said whether the link is dead. | no |
What each redirect type means
redirectKind | Meaning |
|---|---|
same-page | Only https, www or a trailing slash changed. Nothing to fix. |
same-site | Another page on the same site. |
other-site | Another site. The original may be gone, so an archived copy is looked up. |
to-homepage | A deep link that now lands on a front page. The content is usually gone even though the status is 200, so an archived copy is looked up. |
How to use Link Rot Checker
- In the Apify Console. Open the actor page and click Start — the
urlsfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - Via the API. Call it directly with a POST request — no Console needed once you have an API token:
curl "https://api.apify.com/v2/acts/accountable_eel~link-rot-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"urls":["https://example.com","https://example.com/this-page-does-not-exist","https://www.google.com/reader/about/"]}'
- On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
Input
{"urls": ["https://example.com","https://example.com/this-page-does-not-exist","https://www.google.com/reader/about/"]}
One URL per line. Each one is opened the way a browser would open it, redirects are followed, and you get back whether it is alive, redirected or dead. A dead link also gets the newest copy the Wayback Machine saved while the page still worked. Accepted formats: https://example.com/some/page, example.com/pricing, http://old-site.org/article.html.
Output
| query | found | status | sourceUrl | linkStatus | isBroken | statusCode | reason | finalUrl | redirectKind | redirectCount | redirectChain | archiveStatus | archivedUrl | archivedAt | blockedBy | contentType | responseTimeMs | scrapedAt |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| https://example.com | true | OK | <response time (ms)> | 1970-01-01T00:00:00.000Z |
A line that is not a web link, a blocked link and an unreachable link come back as one row with
"found": false and a message that says why. They are never charged.
Example runs
Three inputs that need no credentials of any kind and return rows as they stand. Paste one into the Input tab and press Start.
1. Which of these links are dead, and what can replace them?
{"urls": ["https://example.com","https://example.com/this-page-does-not-exist","https://www.google.com/reader/about/"],"checkArchive": true}
2. A permanent archived address next to every reference, working or not
{"urls": ["https://www.w3.org/TR/html401/","https://www.rfc-editor.org/rfc/rfc2616","https://example.com"],"checkArchive": true,"archiveLiveLinks": true}
3. A fast status and redirect pass over a list, dead links only in the result
{"urls": ["http://example.com","https://example.org/missing-page","https://www.iana.org/domains/example"],"checkArchive": false,"includeKeywords": ["dead"]}
Pricing
Pay-per-event. A flat per-run fee covers session/proxy warmup; each independent
source is billed under its own event, only when that source actually returns
data — see .actor/pay_per_event.json for exact prices. A miss is never
charged.
You pay once per link that got a verdict, and nothing else:
- A blocked link, an unreachable link and a line that is not a URL are free.
- The archived copy is included in the price of the link. There is no separate charge for it.
- A row hidden by "Only keep rows containing" is not returned and not charged, so example 3 above pays for the dead links only.
- Use "Stop after this many results" to put a ceiling on a long list.
Use it from Clay, n8n, Make, or an AI agent
This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.
curl "https://api.apify.com/v2/acts/accountable_eel~link-rot-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"urls":["https://example.com","https://example.com/this-page-does-not-exist","https://www.google.com/reader/about/"]}'
n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~link-rot-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"urls":["https://example.com","https://example.com/this-page-does-not-exist","https://www.google.com/reader/about/"]} (swap in an expression from an earlier node for a real value).
Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~link-rot-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"urls":["{{link}}"]}, mapping the row's link into the urls array.
MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "broken link checker" — the agent will find and run this actor.
Where the data comes from
- The status and the redirect chain come from opening each link once with a normal browser request and following every redirect. Page bodies are not downloaded.
- The archived copy comes from the Internet Archive's public Wayback Machine index. The row carries the newest capture taken while the page still answered normally, not a capture of the error page that replaced it.
Limits, stated plainly
- A blocked link is not a verdict. Some sites refuse every request that does not come from a
home connection. Those rows say
blockedand are free. Open them in a browser to be sure. - A page that says "not found" with status 200 counts as alive. The check reads the status and
the redirects, not the text of the page. A deep link that was redirected to a front page is
flagged as
to-homepage. - The Wayback Machine throttles bulk lookups. On a long list with very many dead links it may
stop answering part-way. Those rows say
RATE_LIMITEDorERRORinarchiveStatus, which means "not known this run", never "no copy exists". Run those links again later. NONEmeans no working capture. A page the archive only ever saved as an error page has no copy worth linking to.- One moment in time. A server that was down for the two attempts is reported as it was. Server errors (5xx) are retried once before they count as dead.
- It checks the links you give it. It does not crawl a site to find links.
- No login, no cookies, no JavaScript. A link that only works when signed in is reported as
blockedwith the reasonLOGIN_REQUIRED.
Data & privacy
The actor opens the URLs you list and reads the public Wayback Machine index. It stores nothing between runs and returns no personal data beyond what your own URLs contain.
FAQ
Why is a link I can open in my browser reported as blocked?
The site refuses automated requests. The row is free, and blockedBy names the protection when it
could be identified.
Why does a dead link have no archived copy?
Either the Wayback Machine never saved the page while it worked (NONE), or it did not answer
during this run (ERROR, RATE_LIMITED).
Is the archived copy the closest one to today? Yes: it is the most recent capture in which the page still returned a normal response.
Can I check thousands of links? Yes. Status checks run in parallel, with no more than two requests at a time to any one site, so a thousand links take a few minutes. An archive lookup can take 10 to 15 seconds and they run three at a time, which is about 900 dead links an hour. For a list with more dead links than that, turn "Find an archived copy for broken links" off for a first pass, then run the dead ones again with it on.
Do I need a proxy? No.
Related actors
- HTTP Status Lookup for status and headers only.
- Redirect Chain Tracer for every hop of a redirect.
- Wayback Machine Snapshot Lookup for a site's first and last capture and its age.
- Soft 404 Detector for pages that say "not found" with status 200.
- Sitemap URL Discovery to get the list of URLs to check.