# Broken Link Checker & URL Status Checker: 404s & Dead Links (`datawright-labs/broken-link-checker`) Actor

Broken links, 404 links and dead links checker: crawl any website and find 404s, 5xx errors, dead domains, timeouts, broken images and redirect chains, with the page and anchor text of each. Callable by AI agents via MCP. $0.50 per 1,000 URLs checked.

- **URL**: https://apify.com/datawright-labs/broken-link-checker.md
- **Developed by:** [Datawright Labs](https://apify.com/datawright-labs) (community)
- **Categories:** SEO tools, Developer tools
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 85.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 url checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**For AI agents:** Use when asked to find broken links or 404s on a site, check dead links in docs, or verify a list of URLs still work. Call with `startUrls` (sites to crawl; required), optional `maxPagesPerSite` (default 200), `maxDepth`, `checkExternalLinks`, `checkResources` (images/scripts/CSS), `outputMode` (`problems`, `problemsAndRedirects`, `all`), `excludePatterns`. Returns one row per bad URL: `status`, `httpStatus`, `error`, `url`, `firstFoundOn`, `anchorText`, `foundOnCount`, `linkType` (redirect rows add `finalUrl`, `redirectCount`). Cost: $0.0005 per unique URL checked ($0.50 per 1,000); each URL charged once per run, robots-blocked and mailto/tel links free.

**For people:** Ask your agent "crawl docs.example.com, find the broken links and tell me which pages to fix" and it runs the crawl here and hands back a fix list: the dead link, the page it is on, and its anchor text. A 200-page site with ~2,000 unique links costs about $1.

**Find every broken link on a website in one run.** Enter a domain, and this broken link checker crawls its pages, checks **every internal and external link** (and optionally every **image, script and stylesheet**), and gives you a clean list of **404s, 410s, 5xx server errors, dead domains (DNS failures), timeouts, TLS errors and redirect chains**, each with the **exact pages and anchor text where the bad link appears**, so you know what to fix and where.

No browser, no install, no desktop crawler licence: it's a fast HTTP link checker that runs in the cloud, handles **many websites per run**, exports to **CSV, Excel, JSON or Google Sheets**, and can run on a **schedule** to catch new dead links before your visitors (and Google) do.

### What does this broken link checker do?

- 🕷️ **Crawls your site** from any start URL (same host, `www.` ignored), up to your page and depth limits, respecting `robots.txt`.
- 🔗 **Checks every link it finds**: internal links, **outbound/external links**, and optionally **images, scripts and CSS** (broken image checker).
- 🚦 **Classifies each URL**: `broken` (404, 410, 5xx, DNS lookup failed, connection refused, timeout, bad TLS certificate, malformed URL), `blocked` (401/403/429/999: the site refused automated checks, verify by hand), `redirect` (works, but via 1+ redirects) or `ok`.
- 📍 **Shows where each broken link is**: `foundOn` lists the source pages with **anchor text**, plus a total `foundOnCount`, so you can fix the most-linked dead URLs first.
- 🔁 **Redirect audit**: final URL and hop count for every redirected link, to clean up redirect chains and update internal links.
- 🧾 A **SUMMARY** record with pages crawled per site, counts per status and the **pages with the most broken links**.
- ⚡ **Fast and light**: header-only checks, parallel requests with a per-host politeness limit, automatic retries for timeouts, 429s and 5xx.

### Use cases

- **SEO audits**: broken internal links waste crawl budget and leak link equity; dead outbound links hurt user trust.
- **Website migrations & redesigns**: verify every old URL still resolves or redirects after a relaunch.
- **Content maintenance**: find dead references in old blog posts, docs and knowledge bases.
- **Agencies**: run one job across all client sites every week and send the report to Sheets or Slack.
- **Link building / outreach**: find broken outbound links on other sites (broken link building).

### How to use it

1. Paste one or more websites into **Websites to check** (e.g. `https://example.com`).
2. Set **Max pages to crawl per site** (start with 50-200) and, optionally, turn on **Check images, scripts and stylesheets**.
3. Click **Start**. Open the **Broken & blocked links** view, or download CSV/Excel.

#### Input example

```json
{
  "startUrls": ["https://example.com", "https://blog.example.org"],
  "maxPagesPerSite": 500,
  "checkExternalLinks": true,
  "checkResources": true,
  "outputMode": "problemsAndRedirects",
  "excludePatterns": ["/tag/", "?replytocom="]
}
```

To check the links on **a single page** only, set `maxDepth` to `0`.

### Output example

```json
{
  "url": "https://example.com/old-pricing",
  "status": "broken",
  "httpStatus": 404,
  "error": null,
  "isInternal": true,
  "linkType": "page",
  "site": "example.com",
  "foundOnCount": 3,
  "foundOn": [
    { "pageUrl": "https://example.com/blog/launch", "anchorText": "see our pricing", "tag": "a" },
    { "pageUrl": "https://example.com/faq", "anchorText": "pricing page", "tag": "a" }
  ],
  "firstFoundOn": "https://example.com/blog/launch",
  "anchorText": "see our pricing",
  "finalUrl": null,
  "redirectCount": 0,
  "contentType": "text/html",
  "responseTimeMs": 182,
  "checkedAt": "2026-10-20T01:00:00.000Z"
}
```

Rows are sorted with broken links first, then blocked, then redirects, each by number of occurrences.

### How much does it cost to check a website for broken links?

You pay **$0.0005 per unique URL checked** ($0.50 per 1,000), whether it's a crawled page or a link target. Every URL is checked once per run even if it appears on hundreds of pages. Excluded URLs, `robots.txt`-disallowed URLs and `mailto:`/`tel:` links are free. No start fee.

| Job | Unique URLs checked (typical) | Cost |
|---|---|---|
| One page's links (`maxDepth: 0`) | ~50-150 | **~$0.03-0.08** |
| Small site, 50 pages | ~500 | **~$0.25** |
| 1,000 unique URLs | 1,000 | **$0.50** |
| Blog/docs site, 500 pages + images | ~5,000 | **~$2.50** |
| Weekly check of 10 small client sites | ~5,000/week | **~$10/month** |

- Apify's **free plan includes $5 of monthly credit**, i.e. about **10,000 link checks a month for free**.
- Paid Apify plans get automatic discounts: **Silver -10%**, **Gold and above -20%**.
- Set **Max pages to crawl per site** and **Maximum cost per run** to hard-cap spend; the Actor stops cleanly at the limit.

### Broken link checker vs. the alternatives

| | This Actor | Free online checkers | Desktop SEO crawlers | Site-audit SaaS |
|---|---|---|---|---|
| No install, runs in the cloud | ✅ | ✅ | ❌ | ✅ |
| Pages per scan | as many as you set | often capped (e.g. a few hundred) | large, limited by your PC / licence | by plan |
| Internal + external + image links | ✅ | partial | ✅ | ✅ |
| Source page + anchor text per broken link | ✅ | sometimes | ✅ | ✅ |
| Many sites per run, API, schedules, webhooks | ✅ | ❌ | ❌ | partial |
| CSV / Excel / JSON / Google Sheets | ✅ | rarely | ✅ | ✅ |
| Cost model | $0.50 per 1,000 URLs, no subscription | free with caps | annual licence | monthly subscription |

### Use it as an API (Python, JavaScript, cURL)

Every Apify Actor is also a REST API, so you can run this broken link checker from your own code, CI pipeline, a no-code tool or an AI agent.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("datawright-labs/broken-link-checker").call(run_input={"startUrls": ["https://example.com"], "maxPagesPerSite": 100})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["status"], item["url"], item["firstFoundOn"])
```

#### JavaScript / Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('datawright-labs/broken-link-checker').call({ startUrls: ['https://example.com'], maxPagesPerSite: 100 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### cURL (run and get results in one request)

```bash
curl -X POST "https://api.apify.com/v2/acts/datawright-labs~broken-link-checker/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"startUrls": ["https://example.com"], "maxPagesPerSite": 100}'
```

Results can also go straight to **Google Sheets, Slack, Make, Zapier, n8n or a webhook** via Apify integrations, and you can run it on a **Schedule** (e.g. every Monday) to monitor for new broken links.

### Use it from your AI agent (MCP)

Your AI assistant or agent can run this Actor as a tool through [Apify's MCP server](https://docs.apify.com/platform/integrations/mcp), so it can run broken link checks on its own while you chat. Add this server to any MCP client that supports remote (Streamable HTTP) servers:

```json
{
  "mcpServers": {
    "datawright-broken-link-checker": {
      "url": "https://mcp.apify.com?tools=datawright-labs/broken-link-checker"
    }
  }
}
```

On first use your browser opens to sign in to Apify (OAuth). If your client can't do OAuth, add `"headers": { "Authorization": "Bearer <YOUR_APIFY_TOKEN>" }` instead. The tool shows up as `datawright-labs--broken-link-checker`, with the same input fields as above, and the agent reads the results with `get-dataset-items`. Then just ask, for example:

> Crawl docs.example.com, find broken links and tell me which pages I need to fix.

Want several Datawright tools at once? Comma-separate them: `https://mcp.apify.com?tools=datawright-labs/broken-link-checker,datawright-labs/pagespeed-auditor`. Runs are billed per result, exactly like normal runs.

### FAQ

#### How do I find broken links on my website?

Enter your domain and run the Actor. It crawls your pages, tests every link, and lists each broken one with the page and anchor text where it appears. Download the list as CSV or Excel and fix the links in your CMS.

#### What counts as a broken link?

A link whose target returns HTTP 4xx (except 401/403/429, which are reported as `blocked`) or 5xx after retries, or that fails with a network error: DNS lookup failed (dead domain), connection refused/reset, timeout or an invalid TLS certificate. Malformed `href` values are reported too.

#### Why are some links "blocked" instead of broken?

Sites like LinkedIn (status 999), some CDNs and bot-protected pages refuse automated requests even though the page works in a browser. They are listed separately so you can verify them by hand instead of chasing false positives. Enabling Apify Proxy can reduce them.

#### Does it check images and other assets?

Yes, turn on **Check images, scripts and stylesheets** to also verify `<img>`, `<script>` and stylesheet URLs (broken image checker).

#### Does it render JavaScript?

No. It reads the HTML your server returns, like a search-engine crawler's first pass. Links that only exist after client-side rendering are not seen. Most CMS, blog, docs and e-commerce sites serve their links in the HTML.

#### Can I check only one page?

Yes. Set **Max crawl depth** to `0` to check all links on the start page(s) only.

#### Will it overload my server?

No. It sends at most **Parallel requests per host** (default 8) requests to one host at a time, uses header-only checks for link targets, and respects `robots.txt`.

#### Can I schedule it and get alerts?

Yes. Create an Apify Schedule (daily or weekly) and connect Slack, email, Google Sheets or a webhook integration to receive new results.

### More tools from Datawright Labs

- [Sitemap URL Extractor](https://apify.com/datawright-labs/sitemap-url-extractor): get every URL of a site from its sitemaps.
- [Bulk PageSpeed & Core Web Vitals Checker](https://apify.com/datawright-labs/pagespeed-auditor): audit PageSpeed / Lighthouse scores for many URLs.
- [Website Screenshot API](https://apify.com/datawright-labs/website-screenshot): bulk full-page screenshots and PDFs.
- [Google Autocomplete Keyword Scraper](https://apify.com/datawright-labs/autocomplete-keyword-scraper): long-tail keyword ideas from Google, YouTube and Bing.
- [Greenhouse, Lever & Ashby Jobs Scraper](https://apify.com/datawright-labs/ats-jobs-scraper): normalized job feeds from 5 ATS platforms.
- [App Store Top Charts & Rank Tracker](https://apify.com/datawright-labs/app-store-top-charts): daily top free/paid/grossing app rankings with rank changes.
- [SSL Certificate Checker](https://apify.com/datawright-labs/ssl-certificate-checker): bulk SSL certificate and domain expiry checks with alerts for expiring, invalid or outdated TLS.
- [Security Headers Checker](https://apify.com/datawright-labs/security-headers-checker): bulk HTTP security headers audit (HSTS, CSP, X-Frame-Options, cookies, HTTPS redirect) with an A-F grade per URL.
- [Redirect Checker](https://apify.com/datawright-labs/redirect-checker): bulk redirect chains (301, 302, meta refresh), final URL and status, loops and old-to-new migration checks.
- [Meta Tags & Open Graph Checker](https://apify.com/datawright-labs/meta-tags-checker): bulk title, meta description, canonical, noindex, hreflang, Open Graph / Twitter card and schema.org checks with an SEO problems list per URL.
- [Tech Stack Detector](https://apify.com/datawright-labs/tech-stack-detector): bulk CMS, ecommerce platform, framework, analytics, CDN, hosting and email provider lookup for any list of websites (7,600+ technologies).
- [SPF, DMARC & DKIM Checker](https://apify.com/datawright-labs/email-domain-dns-checker): bulk email domain audit of SPF (10-lookup limit), DMARC, DKIM, MX provider, BIMI and MTA-STS.
- [WHOIS Domain Lookup (RDAP)](https://apify.com/datawright-labs/whois-rdap-domain-lookup): bulk registrar, domain age, expiry date, nameservers, EPP status and availability from official registry RDAP.

Made by **Datawright Labs**: reliable, fairly priced web data tools. Questions or a missing feature? Open an issue on the Issues tab; we usually reply within a day.

# Actor input Schema

## `startUrls` (type: `array`):

One website or page per line (e.g. https://example.com or example.com). The Actor crawls internal pages from each start URL and checks every link it finds.

## `maxPagesPerSite` (type: `integer`):

How many internal HTML pages to open and scan for links per site. Links found on those pages are all checked, even links to pages beyond this limit (those are checked but not scanned). Tip: also set 'Maximum cost per run' in the run options.

## `maxDepth` (type: `integer`):

How many clicks away from the start URL to crawl. 0 = scan only the start page itself (useful to check a single page's links).

## `checkExternalLinks` (type: `boolean`):

Also check links pointing to other websites (outbound links). Turn off to check internal links only.

## `checkResources` (type: `boolean`):

Also check <img src>, <script src> and stylesheet URLs, to catch broken images and missing assets.

## `outputMode` (type: `string`):

'Problems only' saves broken and blocked links (smallest dataset). 'Problems + redirects' also lists redirected links (good for cleaning up redirect chains). 'Everything' saves every checked URL. You pay per URL checked either way.

## `excludePatterns` (type: `array`):

Don't crawl or check URLs matching any of these patterns. Plain text = case-insensitive 'contains' (e.g. /tag/, ?replytocom=, /cdn-cgi/), \* = wildcard, or a regular expression between slashes.

## `respectRobotsTxt` (type: `boolean`):

Don't crawl or check internal URLs that the site's robots.txt disallows. Turn off only for your own sites.

## `maxSourcesPerLink` (type: `integer`):

For every broken link, list up to this many pages where it appears (with anchor text). The total count is always reported in foundOnCount.

## `maxConcurrency` (type: `integer`):

Maximum requests in flight overall.

## `maxRequestsPerHost` (type: `integer`):

Maximum requests in flight to any single host, to stay polite and avoid rate limits.

## `requestTimeoutSecs` (type: `integer`):

A link that doesn't respond within this time (after 2 retries) is reported as broken with a timeout error.

## `proxyConfiguration` (type: `object`):

Optional. Use Apify Proxy if the site blocks datacenter IPs.

## Actor input object example

```json
{
  "startUrls": [
    "https://crawlee.dev"
  ],
  "maxPagesPerSite": 50,
  "maxDepth": 10,
  "checkExternalLinks": true,
  "checkResources": false,
  "outputMode": "problems",
  "excludePatterns": [],
  "respectRobotsTxt": true,
  "maxSourcesPerLink": 10,
  "maxConcurrency": 20,
  "maxRequestsPerHost": 8,
  "requestTimeoutSecs": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `links` (type: `string`):

Broken, blocked and (optionally) redirected links with the pages and anchor text where they appear.

## `summary` (type: `string`):

SUMMARY record: pages crawled per site, counts of broken/blocked/redirected/OK URLs and the pages with the most broken links.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        "https://crawlee.dev"
    ],
    "maxPagesPerSite": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("datawright-labs/broken-link-checker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": ["https://crawlee.dev"],
    "maxPagesPerSite": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("datawright-labs/broken-link-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://crawlee.dev"
  ],
  "maxPagesPerSite": 50
}' |
apify call datawright-labs/broken-link-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datawright-labs/broken-link-checker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/L4hHVdtyRLQVw6EZB/builds/17Fczt24dWtLYcmho/openapi.json
