Website Link Health - Broken Links & Recovery
Pricing
from $1.20 / 1,000 saved observations
Website Link Health - Broken Links & Recovery
Check links from public HTML pages with referring-page and anchor evidence, redirect chains, confirmed HTTP statuses and saved new/recovered issue tracking. No API key.
Pricing
from $1.20 / 1,000 saved observations
Rating
0.0
(0)
Developer
Brandt May
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Features
Share
Website Link Health — Broken Links & Recovery
Find the exact links that need attention, where they appear, and whether a previously broken target has recovered.
Paste the pages that matter: a pricing page, campaign landing page, documentation index or migration checklist. This Actor reads their static HTML, checks each distinct target once, and returns the source page and anchor text beside the HTTP evidence. Save a baseline to see new issues, persistent failures and confirmed recoveries on later runs.
Workflow guide · More Mayd It data tools · Quality notes
Start in three steps
- Enter the exact Pages to inspect. The included public crawler-test page demonstrates five confirmed404links and one healthy link.
- Keep Check external links enabled if outbound partners and citations matter. Images are optional.
- Run, open Link status and recovery, and filter
linkStatus = broken. Export JSON/CSV or open the readable run report.
{"startUrls": ["https://crawler-test.com/links/broken_links_internal"],"checkExternal": false,"maxLinks": 20,"maxResults": 20}
It checks the links on the supplied pages only. It does not recursively crawl the whole site. Add the important pages explicitly for a predictable scope and bill.
Where it earns its place in your workflow
| Workflow | Useful evidence |
|---|---|
| Website maintenance retainers | New or persistent broken targets with exact referring pages and anchor text |
| Site migrations | Destination URLs and redirect chains for links on your checklist pages |
| Documentation quality | Dead references and recovery after a correction |
| Ecommerce campaign checks | Product and campaign links from landing pages; image src checks when enabled |
| AI retrieval pipelines | HTTP diagnostics before using discovered URLs in a downstream crawler |
What a result looks like
This excerpt shows the shape returned by the included public fixture. Timestamps and source responses vary on each run.
{"url": "https://crawler-test.com/links/not_found/foo1","linkStatus": "broken","httpStatus": 404,"headStatus": 404,"methods": ["HEAD", "GET"],"finalUrl": "https://crawler-test.com/links/not_found/foo1","redirectChain": [],"foundOn": [{"sourcePage": "https://crawler-test.com/links/broken_links_internal","anchorText": "Broken Internal Link 1","kind": "link"}],"comparisonStatus": "not_requested","issueChange": "not_requested"}
One target can appear on several pages. Its foundOn array keeps distinct page/anchor observations, up to100per target; referrersTruncated is explicit if that limit is exceeded. occurrences counts those distinct observations, not duplicate identical HTML tags. Fragment-only links and mailto:, tel:, script, data and unsafe URLs are excluded. URL fragments are removed before deduplication; in-page anchors are not validated.
Read the status correctly
linkStatus | Meaning |
|---|---|
healthy | Final HTTP response is2xx. This does not prove the page's content is correct. |
broken | Confirmed404or410after the negative HEAD response was checked with GET. |
blocked | 401,403,429,451or999; the target may work for a person. No alternate route is tried. |
server_error | 5xxresponse; may be temporary and is not a confirmed dead link. |
client_error | Another4xxresponse; review the recorded status. |
skipped_robots / robots_unavailable | The site's crawl rules prevented inspection or could not be fetched reliably. |
timeout, unreachable, unsafe_target, redirect_limit | The target could not be established within the documented request rules. |
A negative HEAD response is checked once with GET unless it is an explicit access refusal. Only response headers are needed for target status; a2xxsoft404body remains healthy. Redirect chains contain the URL, HTTP status and next destination of each followed hop, up to5hops. A redirect-limit failure is reported separately; it is not assigned an invented final destination.
Saved changes without false recoveries
{"startUrls": ["https://crawler-test.com/links/broken_links_internal"],"checkExternal": false,"comparePrevious": true,"snapshotName": "weekly-link-check","maxLinks": 20,"maxResults": 20}
Run the same watchlist again to compare it. issueChange reports:
new_issue: a currently confirmed broken target without a broken prior observation.persistent_issue: the same target remains confirmed broken.recovered: a previously broken target now returns a2xxresponse.baseline,changedorunchanged: other recorded outcomes.
comparisonStatus, changedFields, previousObservedAt and previous retain the underlying comparison. Set onlyChanges: true to save only changed target snapshots. Referrer text is evidence, but changes to it alone do not count as an HTTP-status change.
History advances only after all selected pages and targets have been checked, outputs saved, and outcomes are determinate. A spending, request, result, time or discovery limit leaves the baseline unchanged. Blocked or unreachable checks also prevent baseline advancement. A target that disappears from the HTML is never marked recovered. Keep the same inputs/limits and baseline label, and avoid overlapping runs on one watchlist.
Three input recipes
The first-run fixture and saved comparison recipe appear above. This second source exercises relative URL resolution:
{"startUrls": ["https://crawler-test.com/links/relative_link/a/b"],"checkExternal": false,"maxLinks": 20,"maxResults": 20}
All three exact recipes are available on the website input recipes.
Pricing and cost control
Base pricing is $0.002 per saved target result ($2per1,000), plus the configured Actor-start event. A saved result includes a diagnostic outcome such as blocked or unreachable. Each distinct target is charged at most once in a run even if several supplied pages link to it. Unchanged targets filtered by onlyChanges do not create charged dataset rows. See the Pricing tab for your plan's current rate.
Use maxLinks, maxResults, maxRequests and the Apify maximum-charge setting to bound work. The included six-target fixture normally saves six rows. Limits are independent: reaching one can produce partial results. The run's SUMMARY explains what was reached and whether history was updated.
Outputs and integrations
- Dataset: one row per saved target, ready for JSON/CSV export.
- SUMMARY: page coverage, request counts, classifications, incomplete work and baseline decisions.
- RUN_REPORT: a self-contained readable report with links to the saved output.
Use Apify schedules for recurring checks and webhooks/integrations to route completed output. For AI agents, use the Actor's native Apify MCP tool or generated OpenAPI endpoint; the website guide includes ready-to-copy API and MCP setup. An HTTP404result is useful audit data and does not itself mean the Actor failed.
Scope and limits
No login, JavaScript execution, proxy, CAPTCHA workaround or form submission. Only public HTTP(S) on ports80/443; each DNS resolution and redirect is checked, and connections use the checked public addresses. Robots rules are respected on each origin, with at least500msbetween request starts to an origin. HTML bodies are capped at2MiB; robots bodies at512KiB; individual request deadlines are bounded. Up to20source pages,500unique targets and180seconds per run are supported.
At most10,000candidate tags per source page are scanned; a larger page reports incomplete discovery. Only a[href], area[href] and optional img[src] are extracted. srcset, CSS backgrounds, scripts, stylesheets, JavaScript-added links, canonical tags and page semantics are outside this Actor's scope. Missing or changed source access is recorded rather than treated as a healthy result.
Need a different extraction source or a reproducible issue fixed? Open an Apify issue with the public URL, input and run link. Do not include credentials or private page content.