# Broken Link Checker: Find 404s, Redirects & Dead Links (`classier_wholemeal/broken-link-checker`) Actor

Broken link checker for SEO audits. Paste URLs, a sitemap, or a starting page. Get HTTP status, redirect chains, response time and error type for every link. No login, no browser, no API key. $0.90 per 1,000 links checked.

- **URL**: https://apify.com/classier_wholemeal/broken-link-checker.md
- **Developed by:** [JackKnifeAI](https://apify.com/classier_wholemeal) (community)
- **Categories:** SEO tools, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 link checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Broken Link Checker: Find 404s, Dead Links, Redirect Chains & SEO Issues

**Broken link checker and dead link finder** for any list of URLs, a website page, or a `sitemap.xml`. Each link is checked with a lightweight HTTP request. You get the status code, final URL after redirects, redirect chain, response time and a clear classification (`ok`, `not_found`, `redirect`, `server_error`, `timeout`, `ssl_error`, …).

No login, no API key, no headless browser and no paid proxy. Built for SEO audits, site migrations, content QA and scheduled health checks.

### Why this broken link checker

| | This Actor | Typical checkers |
|---|---|---|
| Input | URL list, start pages (`<a href>` scan) or sitemap | Often just a URL list |
| Redirect chains | Full chain + hop count | Final status only |
| HEAD with GET fallback | ✅ sites that block HEAD still work | HEAD-only misses many URLs |
| robots.txt on page scans | ✅ respected by default | Rare |
| Return only broken rows | ✅ so you don't pay for healthy links | Often charge every URL |
| Price | **$0.90 per 1,000 links checked** | $1.00–$1.20 / 1,000, sometimes plus a $0.02 start fee |

A popular Store checker in this niche sits around 2.7★ with reports of missed redirects and noisy results. This Actor records the full redirect chain, classifies SSL and timeout errors separately, and lets you export only the rows that need a fix.

### Who uses it

- **SEO agencies:** crawl a client's sitemap or key landing pages and deliver a 404 / redirect report.
- **Site migrations:** confirm old URLs 301 to the right new paths and that nothing 404s.
- **Content and docs teams:** scan published articles for dead outbound citations.
- **Developers:** schedule a daily run and alert Slack when new `not_found` or `server_error` rows appear.

### Example input

Check a mix of known URLs:

```json
{
  "urls": [
    "https://www.python.org",
    "https://www.python.org/this-page-does-not-exist"
  ],
  "onlyBroken": false,
  "maxLinks": 50
}
```

Scan a page for links, then check them:

```json
{
  "startPages": ["https://www.python.org"],
  "checkSameDomainOnly": false,
  "includeResourceLinks": false,
  "onlyBroken": true,
  "respectRobotsTxt": true,
  "maxLinks": 100
}
```

Or paste sitemap URLs to verify every `<loc>`.

### Example output

```json
{
  "url": "https://www.python.org/this-page-does-not-exist",
  "ok": false,
  "classification": "not_found",
  "status": 404,
  "finalUrl": "https://www.python.org/this-page-does-not-exist",
  "redirectChain": [],
  "redirects": 0,
  "contentType": "text/html; charset=utf-8",
  "responseMs": 187,
  "error": null,
  "sourcePage": null,
  "anchorText": null,
  "origin": "direct",
  "checkedAt": "2026-11-06T07:35:00+00:00"
}
```

A `SUMMARY` record in the default key-value store counts links planned vs written, broken down by classification.

### Pricing

Pay per event:

| Event | Price |
|---|---|
| Actor start | $0.00005 |
| Link checked (row written) | **$0.0009** ($0.90 per 1,000) |

Turn on **Return only broken or redirected links** to skip writing (and paying for) healthy `200` responses. Set a maximum charge per run to cap spend.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/classier_wholemeal~broken-link-checker/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://www.python.org", "https://www.python.org/missing"], "onlyBroken": true}'
```

Export as JSON, CSV or Excel, or connect Google Sheets, Zapier, Make, n8n, Slack or webhooks. Works as a tool for AI agents through the Apify MCP server.

### FAQ

**Will this crawl an entire website?** It checks the URLs you give it, every link on the start pages you list, and/or every URL in the sitemaps you paste. It does not spider the whole site recursively, which keeps runs predictable and polite.

**Does it execute JavaScript?** No. Links injected only by client-side JS will not be discovered from start pages. Sitemap and explicit URL inputs do not have that limit.

**Are mailto and tel links checked?** No. They are skipped. So are `javascript:` and in-page `#` anchors.

**Is this allowed?** The Actor sends ordinary HTTP HEAD/GET requests the same way a browser or uptime monitor would, identifies itself with a clear User-Agent, and honors robots.txt when it fetches start pages. You are responsible for checking the sites you target and for how you use the report.

**Why did a working page come back 403 or timeout?** Some hosts treat automated clients differently. The Actor retries transient 429/5xx errors, but it will not rotate proxies or bypass bot protection.

**How is a redirect classified?** Any URL that returns 3xx (or a chain of them) is `redirect`. The full `redirectChain` is included. Turn on *Treat 3xx redirects as issues* if you want those rows when *Return only broken* is enabled.

# Actor input Schema

## `urls` (type: `array`):

Direct list of page or asset URLs to verify. One per line.

## `startPages` (type: `array`):

Fetch each page's HTML and check every <a href> (and optional img/script/link) found on it.

## `sitemapUrls` (type: `array`):

Check every <loc> in these sitemap.xml files (nested indexes supported).

## `checkSameDomainOnly` (type: `boolean`):

Ignore outbound links discovered on start pages. Direct URLs and sitemap URLs are always checked.

## `includeResourceLinks` (type: `boolean`):

When scanning start pages, include src/href from img, script, link\[rel=stylesheet] and source tags.

## `onlyBroken` (type: `boolean`):

Keep 4xx, 5xx, timeouts, SSL errors and (optionally) redirects. Successful 2xx rows are still processed but not written or charged.

## `treatRedirectAsBroken` (type: `boolean`):

When Return only broken is on, also keep redirecting URLs.

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

Skip fetching a start page if robots.txt disallows this User-Agent. Individual URL checks are not blocked.

## `maxLinks` (type: `integer`):

Safety cap of unique URLs verified in this run.

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

How long to wait for each HTTP response before marking the URL as a timeout.

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

How many links to check in parallel.

## Actor input object example

```json
{
  "urls": [
    "https://www.python.org",
    "https://www.python.org/this-page-does-not-exist"
  ],
  "checkSameDomainOnly": false,
  "includeResourceLinks": false,
  "onlyBroken": false,
  "treatRedirectAsBroken": false,
  "respectRobotsTxt": true,
  "maxLinks": 500,
  "requestTimeoutSecs": 15,
  "maxConcurrency": 8
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "urls": [
        "https://www.python.org",
        "https://www.python.org/this-page-does-not-exist"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("classier_wholemeal/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 = { "urls": [
        "https://www.python.org",
        "https://www.python.org/this-page-does-not-exist",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("classier_wholemeal/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 '{
  "urls": [
    "https://www.python.org",
    "https://www.python.org/this-page-does-not-exist"
  ]
}' |
apify call classier_wholemeal/broken-link-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,classier_wholemeal/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/PaKvCbXPt79QwmoVT/builds/PBhh0E46hejLvLLHp/openapi.json
