Broken Link Checker & Redirect Chain Finder
Pricing
from $0.80 / 1,000 link checkeds
Broken Link Checker & Redirect Chain Finder
Crawl a website and check every internal and external link: status code, full redirect chain, broken links (404, timeouts, DNS errors), and the pages and anchor text where each link appears. Honours robots.txt and Crawl-delay. Skipped links are free.
Pricing
from $0.80 / 1,000 link checkeds
Rating
0.0
(0)
Developer
kelp forest
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
9 days ago
Last modified
Categories
Share
Give it your start URL(s). It crawls your own site, collects every link, and checks each unique link once: HTTP status, the full redirect chain, the final URL, and which pages link to it (with anchor text), so you can fix broken links and redirect hops quickly.
Use cases
- Monthly SEO link audits for clients.
- Find redirect chains after a site migration.
- Catch dead outbound links in docs and blogs.
- Pre-launch QA of a new site.
What it does
- Breadth-first crawl of each start URL's host, limited by
maxDepth,maxPagesandmaxLinks. Every start URL crawls its own scope tomaxDepth, even where it overlaps another start URL; a link already checked is not checked or billed again (its row keeps the first start URL that found it, even if that was another site's external link). - Checks internal and (optionally) external links; external links are requested once and never crawled.
- Optional check of images, scripts, iframes and stylesheets (
includeResources). - Each row:
result(ok,redirect,broken, orblockedfor 401/403/429/999 answers, which usually mean a login wall, bot protection or rate limiting rather than a dead link),httpStatus,redirectChain(every hop with its status),finalUrl,foundOn(up to 10 pages),foundOnCount,anchorText,linkType,error(timeout, DNS lookup failed, redirect loop, too many redirects).foundOn/foundOnCountcover the pages seen linking to the URL by the time it was checked (the page that first linked to it is always included). - Results stream into the dataset as links are checked: a timeout, abort or crash loses at most the link in flight.
- Every request has a hard time limit: a link that does not finish within twice
timeoutSecs(all redirects and the page included) is reported as broken (timeout), so a server that trickles bytes cannot stall the run. - Stops cleanly, without making requests it could not bill, when your maximum charge for the run is reached, about 20 seconds before the run timeout (a request still in flight is cut off then, not reported and not billed), or when the run is aborted.
- Uses HEAD for links it does not need to read and re-checks with GET when a server answers HEAD with an error, so servers that mishandle HEAD are not reported as broken.
- A run summary (
SUMMARYrecord) with counts per result,redirectNotFollowed(billed redirects whose destination was not checked), andstopReason(charge_limit,timeout_soon,aborting,max_links, or null when the crawl finished).
Polite by design
- Identified user agent:
KelpForestLabs-LinkChecker/1.1 (+https://apify.com/kelp_forest_labs/broken-link-checker; ...). - Honours robots.txt per host (RFC 9309: 4xx = no rules; 5xx, 429, timeouts and network errors = treat as
disallow-all; a host that does not resolve or refuses connections is reported as broken) and
Crawl-delayup to 10 s; redirects are only followed where the target host's robots.txt allows it (redirectNotFollowedsays why); default delay 0.5 s between requests to the same host. Links robots.txt disallows are listed as freeskippedrows. - No logins, cookies, captchas or proxies. Private, loopback and cloud-metadata addresses are never requested.
Pricing (pay per event)
| Event | Price |
|---|---|
link (one unique link requested and reported) | US$0.0008 |
A link is billed once per run as a checked link, whatever the result: ok, redirect, broken or blocked
(finding broken links is the product), however many pages link to it. blocked results (HTTP 401, 403, 429 or 999)
are billed as checked links: the request was made and answered, even though the site refused it. Not billed: links skipped because of robots.txt, private/reserved targets, mailto:/tel:/javascript:
links, links beyond maxLinks, and an unusable start URL. A link that redirects into a path the target's robots.txt
disallows is billed as a checked link (result: redirect, redirectNotFollowed set): its own URL was requested and
answered, but the destination is not verified, so filter on redirectNotFollowed as well as broken when you look
for dead targets. Use maxLinks to cap spend (500 links = US$0.40).
Each run also has Apify's run-start charge of US$0.00005, once per run for up to 1 GB of memory plus once per extra GB (US$0.00005 at the default 512 MB), charged when the run starts, even if every link is skipped.
How to use
- Open the actor in Apify Console and fill in the input form (or paste the JSON example below into the JSON editor).
- Optional: set a maximum charge for the run under the run options to cap what a run can cost.
- Click Start. Results appear in the Output tab as they are produced; export them as JSON, CSV, Excel or HTML.
You can also start runs from the Apify API or CLI, run the actor on a schedule (for example weekly), and send results to other apps with Apify integrations and webhooks.
Input example
{"startUrls": [{"url": "https://example.com/"}], "maxDepth": 2, "maxPages": 50, "maxLinks": 500, "checkExternal": true}
Output example (local fixture run, Oct 7, 2026)
{"startUrl": "https://example.com/index.html", "url": "https://example.com/gone.html", "linkType": "internal", "tag": "a", "anchorText": "Gone","foundOn": ["https://example.com/index.html", "https://example.com/about.html"], "foundOnCount": 2, "depth": 1,"status": "ok", "result": "broken", "httpStatus": 404, "finalUrl": "https://example.com/gone.html", "redirectChain": [], "redirectCount": 0, "error": null, "method": "GET"}
FAQ
Does it run JavaScript? No. Links added only by JavaScript are not seen.
Is every link charged?
Each unique link checked is charged once per run, whatever the result. Links skipped by robots.txt, private addresses, mailto:/tel: links and links beyond maxLinks are free.
How do I limit cost?
Use maxLinks (500 links = US$0.40) and maxPages, or set a maximum charge for the run: the checker stops before the first link it could not be paid for. Each run adds Apify's run-start charge (US$0.00005 once per run for up to 1 GB of memory, plus once per extra GB: US$0.00005 at the default 512 MB).
What happens if the run times out or is aborted?
Each link is saved the moment it is checked, so nothing checked is lost. The checker stops cleanly about 20 seconds before the run timeout, even in the middle of a slow request (that link is then not reported or billed), and writes its SUMMARY with the reason (stopReason). Each request also has a hard limit of twice timeoutSecs, so one slow server cannot stall the run.
Why is a link blocked and not broken?
HTTP 401, 403, 429 and 999 usually mean a login wall, bot protection or rate limiting: the page may work in a browser. These links were requested, so they are billed like any other result.
Why is a page reported as ok when it shows 'not found'? Soft 404 pages that answer HTTP 200 look fine at the HTTP level; the checker does not judge page content.
Limits: what this actor does not do
- It does not crawl other hosts, log in, run JavaScript or submit forms (links added only by JavaScript are not seen).
- It does not judge content (soft 404 pages that answer 200 are reported as
ok). - It is not a security scanner.
- Hosts that are down: a host that does not resolve or refuses connections is reported as
broken. A host that resolves but never answers makes its robots.txt time out, and its links are then freeskippedrows (notbroken). If a host refused the robots.txt request and comes back later in the same run, its pages may be read without its robots.txt rules (rare; a known limitation).
Changelog
- 1.1 (October 15): robots.txt is checked before every redirect hop; an unreachable or rate-limited (429)
robots.txt now means "disallow everything" (free skipped rows), as RFC 9309 requires.
SUMMARYnow also countsredirectNotFollowed. - 1.0 (October 2026): first public version. Update (October 13): a link to the bare domain (
https://site.com) and tohttps://site.com/is now one link, checked and billed once (scheme/host case, default port and#fragmentspellings are merged too;/pageand/page/stay separate). - Update (October 13, later): with several start URLs, a link reached from more than one of them is checked and billed once per run (its row keeps the first start URL that found it).
- Update (October 14): each start URL again crawls its own scope to
maxDepth(pages already checked from another start URL are re-read for free so their links are found); a malformed start URL (for example a bad port) is a free error row.