Website Link Health - Broken Links & Recovery avatar

Website Link Health - Broken Links & Recovery

Pricing

from $1.20 / 1,000 saved observations

Go to Apify Store
Website Link Health - Broken Links & Recovery

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

Brandt May

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Features

Limited permissions

Share

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

  1. Enter the exact Pages to inspect. The included public crawler-test page demonstrates five confirmed404links and one healthy link.
  2. Keep Check external links enabled if outbound partners and citations matter. Images are optional.
  3. 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

WorkflowUseful evidence
Website maintenance retainersNew or persistent broken targets with exact referring pages and anchor text
Site migrationsDestination URLs and redirect chains for links on your checklist pages
Documentation qualityDead references and recovery after a correction
Ecommerce campaign checksProduct and campaign links from landing pages; image src checks when enabled
AI retrieval pipelinesHTTP 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

linkStatusMeaning
healthyFinal HTTP response is2xx. This does not prove the page's content is correct.
brokenConfirmed404or410after the negative HEAD response was checked with GET.
blocked401,403,429,451or999; the target may work for a person. No alternate route is tried.
server_error5xxresponse; may be temporary and is not a confirmed dead link.
client_errorAnother4xxresponse; review the recorded status.
skipped_robots / robots_unavailableThe site's crawl rules prevented inspection or could not be fetched reliably.
timeout, unreachable, unsafe_target, redirect_limitThe 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, changed or unchanged: 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.