Broken Link Checker: 404s, Dead Links & Redirect Chains
Pricing
Pay per event
Broken Link Checker: 404s, Dead Links & Redirect Chains
Broken links only, without false alarms from bot-blocked sites. Checks every link, image, CSS and JS file on your site for 404s, 5xx, timeouts and redirect chains, with the page and anchor text for each. 403/429/999 are labelled access-denied. $0.0003 per link, $0.0008 per page.
Pricing
Pay per event
Rating
0.0
(0)
Developer
saif alnuaimi
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Broken links only, no false alarms. This broken link checker crawls your website, checks every internal and external link, image, stylesheet and script, and returns one row per problem with the page it's on and the anchor text, so each fix takes a minute. Links that only fail because of bot protection (LinkedIn's 999, 403 or 429 responses) get their own access-denied label, so they don't land in your broken list.
- Finds 404s and other 4xx, 5xx errors, timeouts, DNS/SSL/connection failures, too many redirects and malformed URLs
- Flags redirect chains of 2+ hops
- Labels 401/403/429 and non-standard codes such as LinkedIn's 999 as
access-denied, not broken - Uses HEAD first, then confirms with GET before calling a link broken
- Respects robots.txt, waits between requests to the same host, stays on the start URL's host
- Plain HTTP, no browser: $0.0003 per unique link checked ($0.30 per 1,000 links), $0.0008 per page crawled
Quick start
- Click Start.
- Enter your homepage in Website(s) to audit, e.g.
https://example.com. - Keep the defaults (200 pages, depth 3, external links and images on).
- Optional: set Max cost per run. The Actor stops cleanly when it is reached.
- Run, then open the Link issues table, or export as CSV/Excel and sort by Found on.
{"startUrls": ["https://example.com"],"maxPagesToCrawl": 200,"reportMode": "issues"}
Only want hard failures? Use "reportMode": "broken".
Output
One row per link occurrence, so a dead link that appears on three pages gives three rows (each with its own sourcePageUrl) but is checked and charged only once. Three rows from our latest test crawl of the public docs site crawlee.dev (fields shortened):
[{"linkUrl": "https://github.com//github.com/apify/crawlee/blob/f3eb99d9fa9a7aa0ec1dcb9773e666a9ac14fb76/packages/core/src/storages/sitemap_request_list.ts/issues/L446","statusCode": 404,"isBroken": true,"issueType": "http-4xx","redirectCount": 0,"anchorText": "/github.com/apify/crawlee/blob/f3eb99d9fa9a7aa0ec1dcb9773e666a9ac14fb76/packages/core/src/storages/sitemap_request_list.ts#L446","sourcePageUrl": "https://crawlee.dev/js/api/core/changelog"},{"linkUrl": "https://apify.com/discord","statusCode": 200,"isBroken": false,"issueType": "redirect-chain","redirectCount": 2,"anchorText": "Discord channel","sourcePageUrl": "https://crawlee.dev/blog"},{"linkUrl": "https://stackoverflow.com/questions/tagged/crawlee","statusCode": 403,"isBroken": false,"issueType": "access-denied","redirectCount": 0,"anchorText": "Stack Overflow","sourcePageUrl": "https://crawlee.dev/"}]
The first is a real malformed link (the domain is repeated in the path). The second works but passes through two redirects. The third is a working Stack Overflow page that blocks automated checks; it is not counted as broken.
Run summary for that crawl: 8 pages crawled, 998 unique links checked, about 5 minutes at the default politeness delay, cost ≈ $0.31.
issueType | Meaning | Counted as broken? |
|---|---|---|
http-4xx / http-5xx | Server returned an error (404, 410, 500 …) | Yes |
timeout, dns, ssl, connection | No usable response | Yes |
too-many-redirects, invalid-url | Redirect loop or malformed URL | Yes |
redirect-chain | Works, but goes through 2+ redirects | No (fix for speed and SEO) |
access-denied | 401/403/429/999: usually bot protection | No (check manually) |
ok | Only in all mode | No |
Per-site totals (pages crawled, links checked, issues) are saved in the key-value store as OUTPUT.
Pricing
Pay per event. Output rows are free.
| Event | Price (USD) |
|---|---|
| Actor start | $0.00005 per GB of memory (default 512 MB = one event, $0.00005) |
Page crawled (page-crawled) | $0.0008 |
Unique link checked (link-checked) | $0.0003 |
Each unique URL is checked once per run, however many pages link to it. Example from our test: crawlee.dev, 8 pages and 998 unique links ≈ $0.31. The budget is checked before every page and every link, so "Max cost per run" is respected.
Use cases
- Agencies: schedule a weekly run per client site and send the broken list to email or Slack (Apify schedules + Make, n8n or Zapier)
- Regular SEO and site-health audits
- Checking a site after a migration, redesign or URL change
- Docs and blog maintenance: find outdated external references
- An AI agent tool: "check this site for broken links"
Input options
| Field | Default | What it does |
|---|---|---|
startUrls | (required) | Start pages; the crawler stays on each start URL's host (subdomains are not followed) |
maxPagesToCrawl | 200 | Internal HTML pages to scan per site (max 20,000) |
maxDepth | 3 | Link depth from the start page (0 = start page only) |
checkExternalLinks | true | Also check links to other domains |
checkImagesAndAssets | true | Check <img>, stylesheets and scripts too |
reportMode | issues | issues = broken + redirect chains + access-denied; broken; all |
excludePatterns | [] | Regexes for URLs to skip, e.g. /logout |
respectRobotsTxt | true | Don't crawl pages robots.txt disallows |
maxConcurrency | 5 | Parallel checks (max 20) |
requestDelayMs | 250 | Delay between requests to the same host |
requestTimeoutSecs | 20 | After this, the link is reported as timeout |
Use with AI agents (MCP)
https://mcp.apify.com/?tools=saif-tools/broken-link-checker
Prompt: "Check example.com for broken links and list the pages I need to fix." For agent calls, use reportMode: "broken" and maxPagesToCrawl: 50.
FAQ
How do I find broken links on my website?
Enter your homepage in Website(s) to audit, keep the defaults and run. Export the result as CSV and sort by sourcePageUrl to get a to-do list per page.
Why are some links "access-denied" rather than broken?
StackOverflow and npm returned 403, and LinkedIn returned 999, to our checker during testing, even though the pages work in a browser. Reporting them as broken would be a false alarm, so they get their own label. Open them by hand if in doubt.
What does a redirect chain mean?
The link works but passes through 2 or more redirects before reaching the page. Each hop adds latency and uses an extra crawl request. Update the link to the final URL.
Does it find links added by JavaScript?
No. It reads the HTML the server sends. Links that only appear after JavaScript runs (single-page apps) aren't found.
Will it crawl other websites?
No. It crawls only the start URL's host. External links get one lightweight request per unique URL to check their status.
How long does a run take?
It depends mostly on the per-host delay. Our crawlee.dev test (8 pages, 998 links, 250 ms delay) took about 5 minutes. Lowering requestDelayMs speeds it up; only do that on sites you control.
Can I run it every week and get the results in Slack or email?
Yes. Create an Apify schedule for the Actor, then send the dataset to Slack, email or Google Sheets with Apify's Make, n8n or Zapier integrations: https://docs.apify.com/platform/integrations
Can I audit any site?
Audit sites you own or have permission to audit.
Related tools from saif-tools
SEO toolkit: run the Sitemap URL Extractor to list every URL your sitemaps publish, then this checker to find what's broken on the pages themselves. Together you see what you tell search engines exists and what actually works.