Broken Link Checker & Redirect Chain Auditor avatar

Broken Link Checker & Redirect Chain Auditor

Pricing

from $0.50 / 1,000 link checkeds

Go to Apify Store
Broken Link Checker & Redirect Chain Auditor

Broken Link Checker & Redirect Chain Auditor

Crawl a website to find broken links (404, 5xx), redirect chains, redirect loops, timeouts and mixed content. Polite, robots.txt-aware link audit.

Pricing

from $0.50 / 1,000 link checkeds

Rating

0.0

(0)

Developer

Grace M. Hartwell

Grace M. Hartwell

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

20 hours ago

Last modified

Share

Hartwell Toolworks

Broken Link Checker & Redirect Chain Auditor crawls your website and finds broken links (404, 410, other 4xx, 5xx), redirect chains, redirect loops, timeouts and insecure http / mixed-content links. It checks every internal and external link once (HEAD first, GET as a fallback) and records every redirect hop. You get one clear report row per link, showing the pages where the link appears, so you know exactly what to fix. The crawler respects robots.txt and per-host limits, and it costs $0.50 per 1,000 links checked.

  1. Crawls the internal HTML pages of your site from a start URL, within a maximum depth and page count. robots.txt is respected and crawling is rate-limited.
  2. Collects every link (<a>, <area>) and, optionally, every image, script, stylesheet, iframe and audio/video source, together with the pages and anchor texts where it appears.
  3. Checks each unique URL once: HEAD first, then GET when a server answers HEAD with an error code. Redirects are followed manually, so every hop is recorded.
  4. Retries 429, 5xx and network errors with exponential backoff. Timeouts are not retried, which keeps runs fast.
  5. Reports one dataset item per link (internal links first, then external) and saves a run summary to the OUTPUT record.

What does it find?

Findingstatus / issue code
404, 410 and other 4xx, 5xx responsesbroken / BROKEN (with the final HTTP status)
Redirects, and redirect chains of 2+ hops (every hop listed)redirect / REDIRECT, REDIRECT_CHAIN
Redirect loops (A → B → A)redirect-loop / REDIRECT_LOOP
More redirects than maxRedirectstoo-many-redirects / TOO_MANY_REDIRECTS
No answer within the timeouttimeout / TIMEOUT
DNS, TLS and connection errors, invalid Location headerserror / ERROR (e.g. ENOTFOUND in error)
https page linking to an http:// URLINSECURE_HTTP_LINK
https page loading an http:// image, script, CSS, iframe or media fileMIXED_CONTENT (needs checkResources)
Redirect from https to httpHTTPS_TO_HTTP_REDIRECT
http link that redirects to httpsHTTP_UPGRADED_BY_REDIRECT (update the link)
Internal URL disallowed by robots.txtskipped-robots / ROBOTS_TXT_DISALLOWED (not requested, not charged)

Key features

  • 🔗 Internal and external link checking: external sites get one HEAD/GET check per unique URL and are never crawled.
  • ↪️ Full redirect chains: each hop with its URL, status code and Location, plus the final URL and status.
  • 📍 Where each link appears: up to 10 pages with anchor text and tag (foundOn), plus the total number of occurrences (foundOnCount).
  • 🔒 HTTPS hygiene: finds insecure http:// links, mixed content, and https → http redirects.
  • 🤝 Polite crawling: robots.txt is respected for your site, at most 2 parallel requests per host by default, rate limits for crawling, and a clear user agent (BrokenLinkRedirectAuditor/1.0).
  • 🧾 Issues-only mode: onlyIssues keeps healthy links out of the dataset (they are still checked and counted).
  • 💸 Budget control: maxLinksToCheck and Max total charge stop the run cleanly.

Use cases

  1. Technical SEO audits: find 404s and long redirect chains that waste crawl budget and link equity.
  2. Website migrations: check that old URLs redirect in one hop to the right target, with no loops or https → http downgrades.
  3. Content QA before a launch: catch dead internal links, missing images and broken scripts before visitors do.
  4. Scheduled link monitoring: run weekly on a blog, help center or documentation site with an Apify schedule.
  5. HTTPS clean-up: list remaining http:// links and mixed-content resources on https pages.
  6. Outbound link hygiene: find external links that now return 404 or redirect somewhere else.

The Actor uses pay-per-event pricing:

EventPriceWhen it is charged
link-checked$0.0005 per unique URL checked ($0.50 per 1,000)After a link has been checked (crawling pages is included)
apify-actor-start$0.00005 per runAutomatically at run start (Apify default price)

Each URL is checked and charged once per run, no matter how many pages link to it. URLs skipped because of robots.txt are free. Healthy links hidden by onlyIssues are still checked, so they are still charged.

Example calculation: a 200-page site with 1,500 unique links:

1,500 unique links × $0.0005 = $0.75
+ 1 Actor start × $0.00005 = $0.00005 (default 512 MB memory → 1 start event)
-------------------------------------------------
Total ≈ $0.75005 (= $0.50 per 1,000 links)
  1. Open Broken Link Checker & Redirect Chain Auditor in Apify Store and click Try for free.
  2. Enter your Website (start URL), e.g. https://www.example.org/.
  3. Set Max pages to crawl and Max crawl depth (0 = only the start page).
  4. Choose what to check: external links, images, scripts, stylesheets and iframes (needed for mixed content), and whether to only output links with issues.
  5. Optional: set Max links to check or a Max total charge to limit the cost.
  6. Click Start. Open the Overview table, or export the report as CSV, Excel or JSON. The summary is in the OUTPUT record.

Input example

{
"startUrl": "https://www.example.org/",
"maxPages": 200,
"maxDepth": 3,
"includeSubdomains": false,
"checkExternalLinks": true,
"checkResources": true,
"onlyIssues": true,
"maxLinksToCheck": 0,
"requestTimeoutSecs": 15,
"maxRedirects": 10,
"maxRetries": 2,
"maxConcurrency": 5,
"perHostConcurrency": 2,
"maxRequestsPerMinute": 120
}
Input fieldTypeDefaultDescription
startUrlstringhttps://example.com/Page to start from. Only pages on this host are crawled. Replace the default with your own website.
maxPagesinteger50Internal HTML pages to crawl (1–10,000).
maxDepthinteger30 = only the start page, 1 = plus the pages it links to, … (0–20).
includeSubdomainsbooleanfalseTreat blog.example.com as internal when starting at example.com.
checkExternalLinksbooleantrueAlso check links to other websites (never crawled).
checkResourcesbooleanfalseAlso check images, scripts, stylesheets, iframes and media; detects mixed content.
onlyIssuesbooleanfalseLeave healthy links out of the dataset.
maxLinksToCheckinteger00 = no limit; also capped by Max total charge.
requestTimeoutSecsinteger15Timeout per request (3–120).
maxRedirectsinteger10Longer chains become too-many-redirects (1–30).
maxRetriesinteger2Retries for 429, 5xx and network errors (0–6).
maxConcurrencyinteger5Parallel crawl requests (1–10); link checks use up to 2× this.
perHostConcurrencyinteger2Max parallel link checks per host (1–5).
maxRequestsPerMinuteinteger120Rate limit for crawling your site (1–1,000).

Output example

One dataset item per unique link (example based on a local test run; the host has been replaced):

{
"url": "https://www.example.org/chain-1",
"status": "redirect",
"httpStatus": 301,
"finalUrl": "https://www.example.org/ok",
"finalStatus": 200,
"redirectCount": 3,
"redirectChain": [
{ "url": "https://www.example.org/chain-1", "status": 301, "location": "https://www.example.org/chain-2" },
{ "url": "https://www.example.org/chain-2", "status": 302, "location": "https://www.example.org/chain-3" },
{ "url": "https://www.example.org/chain-3", "status": 307, "location": "https://www.example.org/ok" }
],
"internal": true,
"kind": "anchor",
"issues": ["REDIRECT", "REDIRECT_CHAIN"],
"mixedContentOn": [],
"insecureLinkOn": [],
"foundOn": [{ "page": "https://www.example.org/", "text": "Redirect chain", "tag": "a" }],
"foundOnCount": 1,
"method": "HEAD",
"responseTimeMs": 12,
"error": null,
"checkedAt": "2026-10-25T22:59:05.500Z"
}

Robots.txt-skipped item (free):

{ "url": "https://www.example.org/private/secret", "status": "skipped-robots", "internal": true, "issues": ["ROBOTS_TXT_DISALLOWED"], "foundOn": [{ "page": "https://www.example.org/", "text": "Private", "tag": "a" }], "foundOnCount": 1, "note": "Not requested: disallowed by robots.txt. Not charged." }

Run summary (OUTPUT record, numbers from the local test site):

{
"startUrl": "https://www.example.org/",
"pagesCrawled": 8,
"uniqueLinksFound": 17,
"linksChecked": 16,
"robotsSkipped": 1,
"byStatus": { "skipped-robots": 1, "ok": 8, "broken": 4, "redirect": 1, "redirect-loop": 1, "timeout": 2 },
"byIssue": { "BROKEN": 4, "REDIRECT": 1, "REDIRECT_CHAIN": 2, "REDIRECT_LOOP": 1, "TIMEOUT": 2 },
"stoppedEarly": false
}

Output fields

FieldDescription
urlThe checked URL (fragment removed).
statusok, redirect, broken, timeout, error, redirect-loop, too-many-redirects, skipped-robots.
httpStatusStatus of the first response (e.g. 301), or null.
finalUrl, finalStatusWhere the redirects end and that page's status.
redirectCount, redirectChainNumber of hops and { url, status, location } per hop.
internaltrue if the URL is on your site (subdomains only with includeSubdomains).
kindanchor (link) or resource (image, script, CSS, iframe, media).
issuesIssue codes, e.g. BROKEN, REDIRECT_CHAIN, MIXED_CONTENT.
mixedContentOn, insecureLinkOnUp to 10 https pages that load the resource over http / link to it over http.
foundOn, foundOnCountUp to 10 pages with anchor text and tag; total number of occurrences.
methodHEAD or GET (the method used for the last request).
responseTimeMsTotal time for the check, including redirects and retries.
errorReadable error, e.g. HTTP 404 or HTTP 403 (access denied – may be login/bot protection).
checkedAtTimestamp.

Integrations and API

The report is a standard Apify dataset, so you can use the Apify API, API clients, schedules, webhooks and integrations (for example Make, Zapier, n8n or Google Sheets exports).

curl -X POST "https://api.apify.com/v2/acts/grace_hartwell~broken-link-redirect-auditor/run-sync-get-dataset-items?token=[YOUR_APIFY_TOKEN]" \
-H "Content-Type: application/json" \
-d '{"startUrl":"https://www.example.org/","maxPages":50,"onlyIssues":true}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('grace_hartwell/broken-link-redirect-auditor').call({ startUrl: 'https://www.example.org/', onlyIssues: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const broken = items.filter((i) => i.status === 'broken');

FAQ

Some sites block non-browser clients (bot protection) or require a login. The item then says HTTP 403 (access denied – may be login/bot protection). Check these links manually.

No. Pages are fetched as HTML without a browser, so links that are injected only by client-side JavaScript are not found.

How is a redirect chain counted?

redirectCount is the number of redirect hops. One hop is reported as REDIRECT; two or more hops also raise REDIRECT_CHAIN.

Are external websites crawled?

No. External links get a single check (HEAD, with a GET fallback when needed) per unique URL. Only pages on your start host (and, optionally, its subdomains) are crawled.

Yes, if you turn on checkResources. This is also needed to detect mixed content.

How do I keep the cost under control?

Use maxPages, maxDepth, maxLinksToCheck or a Max total charge. The Actor checks internal links first and stops cleanly at the limit; stoppedEarly in the summary tells you whether the limit was hit.

Is www.example.com treated as the same site as example.com?

Yes. A leading www. is ignored when deciding whether a URL is internal.

Limitations: what this Actor does not do

  • No JavaScript rendering: links added only by client-side scripts are missed.
  • No logins, form submissions or bot-protection bypass. Protected pages may show up as 401/403 broken.
  • Fragments are not checked: #anchor parts are removed, so missing in-page anchors are not detected.
  • Only http(s) links: mailto:, tel:, javascript:, data:, ftp: and similar schemes are ignored.
  • No sitemap import: pages are discovered only by following links from the start URL, within maxDepth and maxPages.
  • Files are checked but not crawled: URLs ending in .pdf, .zip, images, .css, .js and similar are checked, but not parsed for more links.
  • robots.txt applies to your site only: external links are checked without reading their robots.txt (one request per unique URL). robots.txt rules are read from the start host only.
  • Timeouts can take up to about twice requestTimeoutSecs: when the HEAD request times out, a GET request is tried as well, and timeouts are not retried.
  • Link checks are not limited per minute: maxRequestsPerMinute applies to crawling, while link checks are limited by perHostConcurrency and the number of workers.
  • Crawled pages are requested twice (once to crawl and once to check), but they are charged once.
  • No content extraction: apart from links, anchor text and tags, nothing is extracted from your pages.

Author: Grace M. Hartwell