Broken Link Checker from Sitemap avatar

Broken Link Checker from Sitemap

Pricing

from $0.70 / 1,000 link checkeds

Go to Apify Store
Broken Link Checker from Sitemap

Broken Link Checker from Sitemap

Check every page in your XML sitemap for broken links. It reads the sitemap, visits each page and checks the links on it. You get 404s, server errors, redirect chains and slow pages, each with the page it was found on. If a site blocks the run, a row says why. Export to CSV or JSON.

Pricing

from $0.70 / 1,000 link checkeds

Rating

0.0

(0)

Developer

Brian Gomes

Brian Gomes

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 hours ago

Last modified

Share

Find every broken link on your website, starting from your XML sitemap. It opens every page the sitemap lists, checks every link on it and lists each 404, server error, redirect chain and slow link, with the page it's on and the link text.

  • Finds orphan pages. It starts from the sitemap, not a crawl, so it also checks pages no menu links to anymore.
  • Or just one page. List it under Single pages and only that page's links are checked, in seconds, with no sitemap read.
  • Internal and external links. Check only the links within your own site, or every outbound link too.
  • Ready for code and AI agents. Every output field is typed, and agents can run it through Apify's MCP server.
  • Only what changed. Turn on Changes only and a weekly run lists just the links that broke, got fixed or disappeared since last time.
  • Never fails silently. No sitemap, a 403, a 429 or a timeout gives you a row that says what happened.
  • $1 per 1,000 links checked, plus $0.50 per 1,000 pages. A link that's on 200 pages is checked and charged once.

Read this first

Every run ends with a short summary in plain English, so you see what changed without opening the table. It's the first line of the run's status, SUMMARY.md on the Output tab (Summary), and the last row of the dataset (summaryText). A weekly run with Changes only on reads like this:

2 new broken links, 1 fixed. 3 still broken.
## New broken links (2)
- On https://example.com/blog/launch: "see our pricing" https://example.com/old-pricing. HTTP 404.
- On https://example.com/docs/start: "partner guide" https://partner.example.org/guide. HTTP 500.
## Fixed (1)
- https://example.com/careers on https://example.com/about works now (HTTP 200).
## Still broken (3)
3 links broken last run are still broken. Turn on Include still-broken links to list them.
## Unverified (1)
This link answered, but not in a way that shows whether it works. It isn't counted as broken.
- "cookie guide" https://cookies.example.org/, on https://example.com/privacy and 2 more pages. HTTP 403: the site blocks automated checks. It may open fine in a browser.
## Run
500 pages scanned, 3,000 links checked.

A quiet week is one line: "All clear. No new broken links." With Changes only off, the summary lists every broken link, grouped by page.

Quick start

  1. Put your homepage or sitemap URL in Websites or sitemap URLs, or a single page under Single pages.
  2. Click Start. The form starts at 10 pages and up to 100 links, so your first run costs at most $0.11.
  3. Export the results as CSV and fix from the top.

Give it a website or a sitemap URL. It reads the sitemap, checks the status of every page in it, then opens each page and checks the links it finds there. You get one row per problem: a 404, a server error, a redirect or a slow response, with the page the link was found on.

A broken link gets a row on every page it's on, since each one is a place to fix. Anything else gets one row for the whole run, with the number of pages it's on. So a slow login link in your menu is one row, not 200.

Or give it the pages yourself. Each page under Single pages is opened and every link on it is checked, and nothing else: no sitemap, no other pages. That's the quick way to check one blog post, a landing page or a page you just edited.

Here's what five rows look like:

resultlinkUrlstatusCodesourcePage
brokenhttps://example.com/old-pricing404https://example.com/blog/launch
brokenhttps://partner.example.org/guide500https://example.com/docs/start
brokenhttps://example.com/careers404https://example.com/sitemap.xml
redirectedhttp://example.com/about200https://example.com/
ok (slow)https://example.com/files/spec.pdf200https://example.com/docs/api

(Example data. A page from the sitemap that is itself broken shows the sitemap as sourcePage; a page you listed under Single pages shows itself. For a redirected link, statusCode is where the redirects end and redirectCount says how many there were.)

Who uses it

  • SEO audits. Find every broken internal link before a search engine does.
  • After a site migration. Check that every page in the new sitemap loads and nothing still points at an old URL.
  • Content and docs teams. Find links to partner sites and files that have gone dead since the page was written.
  • Scheduled checks. Run it weekly and catch a broken link the week it breaks.

Input

FieldWhat it doesDefault
Websites or sitemap URLsOne or more homepages (https://example.com) or sitemaps (https://example.com/sitemap.xml). It works out which one you gave it. Every page the sitemap lists is checked.none
Single pages (no sitemap)One or more pages (https://example.com/blog/post) to check on their own: each page and every link on it, nothing else. Use it instead of, or as well as, Websites or sitemap URLs; at least one of the two is needed. Listed pages go first, and a page in both is checked once.none
Maximum pages to scanStops after this many pages, your listed pages first, then pages from the sitemap. Use it to test on a big site first.100
Maximum links to checkStops after checking this many unique links.5,000
Check external linksAlso checks links that go to other websites. Off: only links on your own site (with or without www.).on
Include working linksAlso lists links that answered 200 quickly with no redirect. Off: only broken, redirected, slow and unchecked links are listed.off
Slow response threshold (ms)A page or link that takes longer than this to respond is flagged slow, and always listed.3,000
Changes onlyOutput only broken links that are new, fixed or gone since this job's last run. See Changes-only mode.off
Include still-broken linksWith Changes only on, also list links that were broken last run and still are.off
Start changes-only overForget what this job saved. Every broken link counts as new again.off
Maximum concurrent requestsRequests in flight at once, never more than 4 to one site.5
Request timeout (seconds)The most any one page or link request may take, from connecting to the last byte.20

Input field names in the API: startUrls, pageUrls, maxPages, maxLinks, checkExternalLinks, includeOkLinks, includeNotChecked, slowThresholdMs, onlyChanges, includeStillBroken, resetChanges, maxConcurrency, requestTimeoutSecs.

The form starts small: 10 pages and up to 100 links, so your first run costs at most $0.11. Raise both when you're ready for the whole site.

Example input:

{
"startUrls": [{ "url": "https://example.com" }],
"checkExternalLinks": true,
"maxPages": 500
}

Example input for one page:

{
"pageUrls": [{ "url": "https://example.com/blog/launch" }]
}

Output

One row per broken link on each page it's on. Redirected, slow and unverified links get one row for the whole run, with pageCount. So do working links, with "Include working links" on. Plus a row for anything it couldn't read. Export it from the Console as CSV, JSON, Excel, XML or HTML, or read it through the Apify API.

FieldWhat it holds
typelink for a page or link that was checked, error for something it couldn't read (no sitemap, a sitemap that failed), summary for the run's summary, always the last row.
resultbroken (4xx other than 429, 5xx, timeout, unreachable or a malformed URL; another site's 401 or 403 is unverified), redirected (ended on a working page after one or more redirects), ok, unverified (a 429 rate limit, another site that blocks automated checks with a 401 or 403, or a redirect into a page robots.txt disallows), not-checked (robots.txt said no, it was over maxLinks, or the run stopped first; error says which; only listed when includeNotChecked is on, otherwise counted by reason in the run's status message), or error. Empty on a removed row in changes-only mode.
sourcePageThe page the link was found on. For a link listed once (pageCount set), the first page it was found on. For a page from the sitemap, the sitemap it's listed in. For a page you listed, the page itself.
pageCountHow many pages the link is on. Set on every link that isn't broken, since it's listed once. Empty on a broken link, which gets a row per page.
linkUrlThe link that was checked.
anchorTextThe link's visible text (or its image's alt text), up to 300 characters.
isInternaltrue when the link is on the same site as your input website or page (with or without www.).
statusCodeThe HTTP status code it ended on.
finalUrlWhere the URL ends up after redirects.
redirectCountHow many redirects it followed.
responseTimeMsTime to the response headers, in milliseconds, redirects included.
slowtrue when the response took longer than your threshold.
foundInpage for a link found on a page, sitemap for a page listed in the sitemap, input for a page you listed under Single pages.
errorEmpty when the row is fine. Otherwise it says what went wrong, like HTTP 404, timed out after 20 s or not checked: disallowed by robots.txt.
startUrlThe input this row came from: the website, the sitemap or the listed page.
changeOnly in changes-only mode. new, fixed, removed or still-broken.
previousStatusCodeOnly in changes-only mode. The status code from the last run, for a link that was broken then.
summaryTextOnly on the summary row. The run in plain English, the same text as SUMMARY.md (see Read this first).

Example row (JSON):

{
"type": "link",
"result": "broken",
"sourcePage": "https://example.com/blog/launch",
"pageCount": null,
"linkUrl": "https://example.com/old-pricing",
"anchorText": "see our pricing",
"isInternal": true,
"statusCode": 404,
"finalUrl": "https://example.com/old-pricing",
"redirectCount": 0,
"responseTimeMs": 212,
"slow": false,
"foundIn": "page",
"error": "HTTP 404",
"startUrl": "https://example.com/"
}

Turn on Changes only and each run lists only what changed since the same job's last run. A link here means one link on one page, so the same broken URL on two pages is two rows. Each row gets a change value:

  • new: broken now, and not broken (or not there) last time.
  • fixed: broken last time, and now it answers (ok or redirected).
  • removed: broken last time, and not found this time. The page no longer links to it, or the page is gone. This is only reported after a complete run: every sitemap and page it meant to read, and no early stop. After a partial run the status message says removals weren't reported, and those links are kept for next time.
  • still-broken: broken both times. Only listed with Include still-broken links on.

Only broken links are compared. Redirected, slow, unverified, working and not-checked links aren't listed in this mode, except a broken link that now works, which is listed as fixed. A broken link that couldn't be checked this time (robots.txt, a 429, a blocked check, or the run stopped) stays broken as far as the next run knows.

Error rows are always listed.

The first run has nothing to compare with. Every broken link is output, marked new.

A job is the same start URLs and single pages (in any order), Maximum pages, Maximum links and Check external links setting. Changes only works on single pages too: a page you list is compared with that page last run. Change any of those and it's a new job, with its own first run.

Where the state lives. What each job found broken is kept in your own Apify account, in a key-value store named broken-link-checker-changes. It holds the page, the link, its status code and the start URL, nothing else.

Starting over. Run the job once with Start changes-only over on. Or delete its record (job-...), or the whole store, under Storage in the Apify Console.

Limits. A job keeps at most 20,000 broken links and 5 MB. A run that would go past that stops early and says why in its status. It counts as a partial run, so it reports no removals.

It stops before the work that wouldn't fit. A page that wouldn't fit isn't read or charged. A page whose links wouldn't fit is read and charged, but its links aren't checked or charged.

What it costs: the normal price, even when nothing changed and no rows come back. Every page is still scanned and every link checked. That work is what's charged, whether or not a row is output.

You pay per page scanned and per link checked, in changes-only mode too. There's no monthly fee.

  • Each page that answers, from the sitemap or your Single pages list: $0.0005 (50 cents per 1,000 pages).
  • Each link checked: $0.001 (1 dollar per 1,000 links), on top of the page price. A link that appears on many pages is checked and charged once. If it's broken, it's reported on every page it's on. If not, it's reported once, with its page count. A link to a page it has already opened isn't checked or charged again.
  • Not charged: anything robots.txt disallows, links it never requested because the run stopped, links and pages that time out or can't be reached (reported as broken, with the reason), links and pages that answer 429, links to other sites that answer 401 or 403 (both reported as unverified), and malformed links (reported as broken without a request).

A worked example. A site has 500 pages in its sitemap and 3,000 unique links across them.

  • Pages and links: 500 × $0.0005 + 3,000 × $0.001 = $0.25 + $3.00 = $3.25.
  • Internal links only (Check external links off): the same sum with only the links on your own site counted. If 1,200 of the 3,000 are internal, that's $0.25 + $1.20 = $1.45.

One page with 80 unique links costs 1 × $0.0005 + 80 × $0.001 = $0.0805.

Apify also charges its standard start fee for each run. Set Maximum pages, or a maximum cost per run, for a hard ceiling: the run checks nothing it can't charge for, stops cleanly when it reaches your maximum cost, and its status line says so.

How it handles the hard cases

  • No sitemap. You get one row with the error "no sitemap found" and nothing else is charged. The run finishes normally.
  • Nested sitemap indexes and gzipped sitemaps. It reads them the same way as Sitemap URL Extractor & Status Checker.
  • 403 and 429. A 429 means the site rate-limited the check, which says nothing about the link. So it's listed as unverified, not broken, and it isn't charged. It doesn't retry a 429 in this version.
  • Sites that block automated checks. Many sites answer 401 or 403 to every automated client, while the page opens fine in a browser. On another site, that's listed as unverified with the reason, and not charged. On your own site a 401 or 403 is reported as broken, since it's yours to look at.
  • Redirect chains. It follows up to 10 redirects and records how many it took. A link that redirects is reported even when it ends on a 200, so you can point it at the final URL. Each hop is checked against robots.txt first. A redirect into a page robots.txt disallows isn't followed, and the link is listed as unverified. Shopify's customer login link does this.
  • A site that stops answering. After 20 requests in a row get no answer (or 10 minutes spent waiting on them), the run stops and its status line says why, rather than timing out page after page for hours. Those requests aren't charged.
  • Typos in links. A link with a broken host name (like http://www..example.com/) or a bad port is reported as broken, with the reason, and the run carries on.
  • Private addresses. It never connects to a private, internal or loopback address, even when a page links there or a redirect points there. Those links are listed with the reason.
  • Spreadsheet safety. Anchor text that starts with =, +, - or @ gets a leading ' so a CSV opened in Excel or Sheets can't run it as a formula.
  • Timeouts. A page or link that doesn't answer in time is recorded as an error row. The timeout covers the whole request, from connecting to the last byte, and is 20 seconds unless you change it. The row's error says timed out after 20 s.
  • robots.txt. It respects robots.txt on your site, on every site it checks a link on and on every redirect it follows. A disallowed URL is counted in the status message (listed only with includeNotChecked on), not fetched, and not charged. A page you listed under Single pages that robots.txt disallows always gets an error row that says so. If robots.txt itself returns a server error, it requests nothing else on that site and counts those links as not checked. If the site can't be reached at all (no DNS, connection refused, timeout), its links are reported as broken, with the reason, and not charged.
  • Load on the site. At most 4 requests at a time to any one host, and it honours a Crawl-delay of up to 10 seconds; a site asking for longer has its URLs counted as not checked rather than holding your run for hours. It identifies itself with an honest user agent, SitemapBrokenLinkChecker/0.1. The agent names a desktop system, so sites like YouTube don't send it to their mobile pages.

You can do this for free. Google Search Console lists 404s that Google found on your site. The W3C Link Checker checks one page's links in a browser. Desktop crawlers like Screaming Frog check a whole site, and the free version stops at 500 URLs. For a small site, one of those is enough.

This Actor fits when the site is bigger, when you want it on a schedule, or when you want the result in your own code through the API. It runs in the cloud, so nothing has to stay open on your computer.

Compared with other broken link checkers in the store, the difference is the starting point. It checks every page the sitemap lists, including orphan pages a crawl would never reach. And a site it can't read gives you a row that says why, not a failed run.

FAQ

How do I find orphan pages with broken links? Give it your sitemap. Every page the sitemap lists is checked, even if nothing on the site links to it anymore. A crawler that only follows links never finds those pages.

How do I find broken links on my website? Put your homepage or sitemap URL in the input and run it. Every row in the result is a page or link that returned an error, redirected, was slow or couldn't be checked, and result says which. Export it as CSV and fix from the top.

What counts as a broken link? Any link that returns a 4xx or 5xx status, times out or can't be reached. Redirects and slow responses are reported too, but they're flagged separately (result is redirected; slow is true) so you can tell them apart. A 429 isn't broken: the site rate-limited the check, so the link is unverified. Neither is a 401 or 403 from another site, which usually means it blocks automated checks.

Why was I charged for links that weren't broken? Every link has to be checked to know whether it's broken. With "Include working links" off, the good ones are left out of the dataset, but they were still checked. A link on many pages is charged once.

Does it check links to other websites? Yes, with "Check external links" on. Turn it off to check only links within your own site.

Why did my run return nothing? Check the error field. It says "no sitemap found", a status like 403, or a timeout. If your sitemap lives somewhere unusual, put its full URL in the input instead of the homepage.

Does it respect robots.txt? Yes, on your site, on every site it checks a link on and on every redirect. It also limits how fast it requests pages from any one host.

Can I run it on a schedule? Yes. Use Apify Schedules to run it weekly with the same input. Each run makes a new dataset, so you can see what broke since last time.

Can I check a single page for broken links? Yes. Put the page under Single pages (pageUrls in the API) and leave Websites or sitemap URLs empty. It opens that page and checks every link on it, internal and external, and reads no sitemap, so it's done in seconds. You pay for one page and the links on it. List more pages the same way.

Can an AI agent run it? Yes. Claude, ChatGPT and other MCP clients can find and run it through the Apify MCP server. It needs one input, startUrls for a whole site or pageUrls for single pages, there's no API key or login, every output field is typed and described in the dataset schema, and it's approved for Apify's agentic payments, so an agent can pay for its own runs.

Can I call it from my own code? Yes. Start it and read the results through the Apify API or the Python and JavaScript clients. It also works with webhooks, Make, Zapier and Google Sheets.

Limits

  • It checks the pages in your sitemap (and any pages you list) and the links on them. It doesn't follow links further than that, so a page that isn't in the sitemap is only checked if a sitemap page links to it, and its own links aren't followed.
  • It reads links from the HTML as served. Links added later by JavaScript aren't seen.
  • It checks links in <a href> (and image-map <area href>) only. Images, scripts and stylesheets aren't checked in this version. It reads the first 5 MB of each page and the first 5,000 links on it; a page past either limit says so in a row.
  • It works on public pages. It doesn't log in.
  • It reads XML sitemaps, including gzipped ones. Plain-text and RSS sitemaps aren't read in this version.
  • It runs in 256 MB by default. A sitemap file over 55 MB uncompressed is refused.

Integrations

This Actor runs on Apify, so everything the platform does works with it.

  • API. Start a run and read the results from your own code, in any language. Apify API
  • Schedules. Run it weekly and catch a broken link the week it breaks. Schedules
  • Tasks. Save your input once as a task and run it again with one click, or on a schedule. Tasks
  • Webhooks. Get a call to your own URL when a run succeeds or fails. Webhooks
  • Google Sheets and Drive. Download the results as CSV or Excel and open them in Sheets. Or add a Google Sheets step after this Actor in Make or Zapier. Or send the files to a Google Drive folder. Datasets and exports, Google Drive
  • Zapier, Make and n8n. Start a run from another app and send the results on to the next step. Zapier, Make, n8n
  • AI agents (MCP). Claude, ChatGPT and other MCP clients can find and run this Actor through the Apify MCP server. Apify MCP server
  • Other Actors. Pass this Actor's results to another Actor when a run finishes. Actor-to-Actor

The SEO toolkit

Five Actors that work together. All are priced per result, with no monthly fee.

ActorWhat you getPrice
Website SEO Audit & CrawlerA 0–100 SEO score and a fix list for every page, with week-over-week changes$5 / 1,000 pages
Broken Link Checker (this one)Every 404, server error and redirect chain, with the page it's on$1 / 1,000 links
Bulk PageSpeed InsightsLighthouse score and Core Web Vitals for every URL, mobile and desktop$2.50 / 1,000 tests
Sitemap URL ExtractorEvery URL in a site's sitemaps, with lastmod and status codes$0.50 / 1,000 URLs
Website Screenshot APIA clean full-page screenshot of every URL, with cookie banners and pop-ups hidden$8 / 1,000 screenshots

Support

Found a bug or need a feature? Open an issue on this Actor's Issues tab. Include the run ID and the URL you gave it.

If it saved you time, a quick review on the Reviews tab helps other people find it.