Broken Link Checker avatar

Broken Link Checker

Pricing

from $0.40 / 1,000 links

Go to Apify Store
Broken Link Checker

Broken Link Checker

Crawls a website from a start page or sitemap and checks every link and image once. Each broken link comes with the page it is on, its anchor text, link type and status, and scheduled runs flag links that broke or were fixed since the last run.

Pricing

from $0.40 / 1,000 links

Rating

0.0

(0)

Developer

deriverge s.r.o.

deriverge s.r.o.

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Broken Link Checker crawls the pages of a website from a start page or from its sitemap, collects every link and image on them and checks each unique target once. Each row is one broken link on one page: the link, the page it was found on, its anchor text, link type, status code or error class. Enter your site in Start URLs and click Start; the prefilled practice site has broken images on purpose. Links to sites behind bot protection are reported as restricted, since their status cannot be verified. It costs $0.80 per 1,000 links on the Free plan ($0.40 on Business), and the $5 of monthly credit in Apify's Free plan covers about 6,200 links.

What data does it return?

FieldDescription
urlThe link target as an absolute URL, such as https://example.com/old-page.
foundOnThe crawled page that contains the link. For pages read from a sitemap it is the sitemap, and for the start URL itself it is empty.
anchorTextVisible text of the link. For a linked image or an <img> it is the alt text, and for an hreflang alternate the language.
linkTypelink (<a href>), image (<img src>), script, stylesheet, icon, canonical, alternate (hreflang), other (another <link href>), start URL or sitemap.
resultbroken, or with Output all links also ok, restricted (login or bot protection, could not be verified) and not checked (robots.txt, a limit, or links to other sites switched off).
statusHTTP status code of the final answer, such as 404 or 500. Empty when no answer came.
errorClass, errorWhy there was no usable answer: dns, timeout, tls, connection_refused, connection_reset, redirect_loop, too_many_redirects and others, with a sentence such as The domain does not resolve in DNS.
isInternaltrue when the link points to the crawled site, with or without www..
nofollowtrue when the <a> tag has rel="nofollow".
finalUrl, redirectCountWhere the link ends up and through how many redirects. A link that works only through a redirect is worth updating.
changeWith a watch name: newly broken, still broken or fixed since the last run.
checkedAtWhen the row was written, as an ISO 8601 UTC timestamp.
  1. Enter the home page or any page in Start URLs, such as https://www.example.com/. To check exactly the pages of a sitemap, enter the sitemap instead, such as https://www.example.com/sitemap.xml; sitemap indexes and .xml.gz files are read too.
  2. Set Maximum pages per site. The crawl goes breadth first, so the pages closest to the start come first. Stay in the start folder keeps it under one section such as /docs/, and Maximum click depth limits how far it goes.
  3. Choose what to check: Check images is on by default, Check scripts, stylesheets and head links adds <script src>, stylesheets, icons, canonical and hreflang links, and Check links to other sites can be turned off for an internal-only audit.
  4. Add texts to Skip URLs containing for links you never want requested, such as /logout or /cart/add.
  5. Click Start. Broken links appear in the Output tab, where you can export them as CSV, Excel or JSON. Turn on Output all links for a full inventory of every link on every crawled page.

Over the API, an input looks like this:

{
"startUrls": ["https://www.example.com/"],
"maxPages": 500,
"checkImages": true,
"checkScriptsAndStyles": false,
"excludeUrls": ["/logout"],
"watchName": "example-weekly"
}

Example output

One row from a run on 11 October 2026, a missing image on the practice site:

{
"url": "https://the-internet.herokuapp.com/asdf.jpg",
"result": "broken",
"status": 404,
"errorClass": null,
"error": null,
"foundOn": "https://the-internet.herokuapp.com/broken_images",
"anchorText": null,
"linkType": "image",
"isInternal": true,
"nofollow": false,
"finalUrl": "https://the-internet.herokuapp.com/asdf.jpg",
"redirectCount": 0,
"change": null,
"checkedAt": "2026-10-11T15:34:33.788Z"
}
Free planStarterScaleBusiness
1,000 links$0.80$0.64$0.52$0.40

You pay only for the events in the table. There is no start fee, and compute time and proxies are included.

You pay per unique link checked, and every crawled page counts as one link because it is requested too. A crawl of 300 pages of the Python documentation found 13,878 links pointing to 2,155 unique addresses and checked 1,725 of them, which costs $1.38 on the Free plan and $0.69 on Business; the rest were on GitHub after it asked to slow down, or disallowed by robots.txt. A link that appears on every page, such as a menu item, is charged once. Links skipped by robots.txt, by Skip URLs containing or by a limit are not charged, and rows in the dataset cost nothing on top.

Limits

  • Only pages on the host of the start URL are crawled (www. and the bare domain count as one site). Links to other sites get one request each and are never crawled.
  • A crawl covers up to 20,000 pages per site (Maximum pages per site) and up to 200,000 unique links per run (Maximum links to check, 5,000 by default), so a run cannot grow without bound. Internal pages beyond the page limit are still checked with a single request.
  • robots.txt of the crawled site is respected for every page and every link on that site, for User-agent: * or for the product token of your User agent. A Crawl-delay is honored up to 20 seconds, with one request at a time. A robots.txt that cannot be read after three attempts (a 5xx answer or no answer) is treated as disallowing the whole site, as the robots.txt standard requires.
  • Each host gets at most 3 parallel requests by default. A 429 answer pauses that host and slows it to one request at a time, and after five 429s its remaining links are not checked. Sites that rate-limit, such as GitHub, can make a run take minutes longer.
  • A 502, 503 or 504 slows that host to one request per second, and the link is tried once more before it counts as broken.
  • When a site answers with a bot protection challenge (Cloudflare, DataDome, Akamai, Imperva, PerimeterX, AWS WAF, Anubis, LinkedIn's 999), its links are restricted and no further requests go to it. The actor does not try to get around protection, and if the crawled site itself is protected, the crawl stops there.
  • Links are read from the HTML the server sends. Links added by JavaScript after the page loads are not seen, because pages are not rendered.
  • A link is tried with HEAD first and with GET when the server refuses HEAD. A link is broken on a 4xx or 5xx answer, a DNS error, a timeout (15 seconds by default), a TLS error, a refused or reset connection or a redirect loop. 401 and 407 count as restricted.
  • Speed on 11 October 2026: the practice site prefilled in the form (18 pages, 85 links) took under a second of crawling, 30 sitemap pages of crawlee.dev with 534 links took 13 seconds, and 300 pages of the Python documentation with 1,725 links took under 3 minutes, most of it spent on links to GitHub, which allows only a slow pace.

Give the run a Watch name, or save the input as a task, and schedule it weekly or daily. Each broken link is then marked newly broken or still broken, links that were broken last time and work now are added as rows marked fixed, and a CHANGES record lists:

  • newlyBroken: links broken now that were not broken in the previous run, with up to five pages they are on.
  • fixed: links that were broken and now work.
  • stillBroken: how many broken links are left from last time.
  • noLongerLinked: broken links from last time that no page links to anymore. It is filled only after a run that crawled the whole site within its limits.

FAQ

The actor reads public pages the way a search engine crawler does, follows the site's robots.txt and keeps the request rate low, and it checks links on other sites with a single request each. It stores links, anchor texts and HTTP statuses, not page content. Check your own sites or sites you have permission to audit, and follow their terms.

Some sites, such as LinkedIn and sites behind Cloudflare challenges, refuse requests from data centers. The actor marks those links restricted and moves on instead of guessing. The SUMMARY record lists every host that stopped answering normally.

Where do I see how much of the site was crawled?

The SUMMARY record in the key-value store has the pages crawled, links found and checked, broken links by link type and by reason (404, 500, dns, timeout), pages left out at Maximum pages per site, pages disallowed by robots.txt and the robots.txt status of each host.

Support

This actor is built and maintained by deriverge s.r.o., a software company based in the Czech Republic. If a run fails or a field you need is missing, please open an issue in the Issues tab or write to us at info@deriverge.com. We respond in English and Czech. Runs can be scheduled in Apify Console or started from the API tab, which has examples for Python, JavaScript and cURL and works with Make, Zapier, n8n and the Apify MCP server. If the actor saves you time, a short review helps other people find it.