# Broken Link Checker - 404s, Redirects & Images, $1/1K Pages (`plotpointtech/broken-link-checker`) Actor

Crawl your website and test every link, image, script and stylesheet for 404s, server errors, timeouts, dead domains and redirect chains. One row per problem with the page it is on. $1 per 1,000 pages crawled, any number of links.

- **URL**: https://apify.com/plotpointtech/broken-link-checker.md
- **Developed by:** [Plot Point Technologies](https://apify.com/plotpointtech) (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.62 / 1,000 page 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

## Broken Link Checker: 404s, Redirects and Dead Images

**Find every broken link on your website in one run.** This broken link checker crawls your site, tests every link, image, script and stylesheet it finds, and gives you one row per problem: the page it is on, the link, its anchor text, the status code or error, the full redirect chain and a severity so you know what to fix first.

You pay **per page crawled ($1 per 1,000 pages)**, not per link or per broken link. A page with 300 links costs the same as a page with 3.

### What does Broken Link Checker do?

- **Crawls your website** from a start URL, following internal links up to a depth you choose, and also reads your **XML sitemap** so pages nothing links to are checked too.
- **Checks every link and file** on each page: internal links, external links, images (`<img>`), scripts (`<script src>`) and stylesheets.
- **Uses HEAD, then GET.** Each URL is tested with a light HEAD request. If that fails, it is re-tested with a normal GET before being reported, so servers that mishandle HEAD do not create false alarms.
- **Follows and records redirects**: every hop with its status code, the final URL, redirect loops, too many redirects and HTTPS-to-HTTP downgrades.
- **Detects** 404 and 410 pages, 5xx server errors, timeouts, DNS failures (domain no longer exists), SSL errors, refused connections and links blocked by bot protection.
- **Is polite**: respects robots.txt, limits parallel requests per host, retries once with back-off and identifies itself as `PlotPointBot`.
- **Checks each URL once per run**, even when it appears on hundreds of pages, but reports every page where a broken link appears so you know exactly where to edit.

### Who uses it?

- **SEO agencies and consultants** running technical audits and monthly link-health reports for clients.
- **Website owners and marketing teams** cleaning up after a redesign, CMS migration or domain change.
- **Developers and QA** checking a staging or production site before launch, or on a schedule.
- **Content and documentation teams** finding outbound links to pages that moved or disappeared.

### How to use it

1. Click **Try for free** (or **Start**).
2. Enter your website's home page (or a section, such as `https://www.example.com/blog/`) under **Websites to check**.
3. Set **Maximum pages to crawl per website**. This is also your cost limit.
4. Optional: turn on **Also report redirects**, turn off **Check links to other websites**, or limit the crawl with **Only crawl pages matching** / **Do not crawl pages matching**.
5. Run it and open the **Broken links** table, or export to CSV, Excel or JSON. Sort by `severity` to fix the worst problems first.

### Input

| Field | Default | Description |
|---|---|---|
| `startUrls` | crawler-test.com | Home page or section of each site to crawl |
| `maxPages` | 20 | Maximum pages crawled per website (the billed unit) |
| `maxDepth` | 3 | Clicks away from the start URL to follow; 0 = start page only |
| `onlyBroken` | true | Only problem links; turn off to get a row for every link |
| `includeRedirects` | false | Also report links that redirect, with the full chain |
| `checkExternal` | true | Also check links and files on other domains (never crawled) |
| `checkAssets` | true | Check images, scripts and stylesheets as well as links |
| `useSitemap` | true | Also crawl pages listed in the XML sitemap |
| `includePatterns` / `excludePatterns` | empty | Regular expressions or `*` wildcards that limit which pages are crawled |
| `maxConcurrencyPerHost` | 4 | Parallel requests to any one server |
| `timeoutSecs` | 15 | Seconds before a link is reported as a timeout |

### Input example

```json
{
  "startUrls": [{ "url": "https://www.example.com/" }],
  "maxPages": 500,
  "maxDepth": 5,
  "onlyBroken": true,
  "includeRedirects": true,
  "checkExternal": true,
  "excludePatterns": ["/tag/", "\\?page="]
}
```

### Output example

One record from the default run on crawler-test.com (a public test site built for crawlers):

```json
{
  "sourcePage": "https://crawler-test.com/",
  "linkUrl": "https://crawler-test.com/redirects/redirect_to_404",
  "anchorText": "Redirect To 404 Http Status",
  "linkType": "internal",
  "statusCode": 404,
  "error": null,
  "redirectChain": [
    { "url": "https://crawler-test.com/redirects/redirect_to_404", "statusCode": 302 }
  ],
  "finalUrl": "https://crawler-test.com/redirects/redirect_to_404_target",
  "isRedirectLoop": false,
  "severity": "critical",
  "result": "broken",
  "problem": "HTTP 404 Not Found",
  "isInternal": true,
  "nofollow": false,
  "occurrencesOnPage": 1,
  "checkedWith": "GET",
  "depth": 0
}
```

#### Output fields

| Field | Description |
|---|---|
| `sourcePage` | Page where the link was found |
| `linkUrl`, `anchorText` | The link and its text (alt text for images) |
| `linkType` | `internal`, `external`, `image`, `script` or `css` |
| `statusCode`, `error` | Final HTTP status, or the network error (timeout, DNS, SSL, refused) |
| `redirectChain`, `finalUrl`, `isRedirectLoop` | Every redirect hop, where it ended, and loop detection |
| `result` | `broken`, `restricted` (401/403/429 or bot protection), `redirect`, `ok` or `skipped` |
| `severity` | `critical` (broken on your own site), `high` (broken external link), `medium` (blocked, timeout on another site, redirect chain or HTTPS-to-HTTP), `low` (single redirect), `ok` |
| `problem` | Plain-English description |
| `isInternal`, `nofollow`, `occurrencesOnPage`, `checkedWith`, `depth` | Extra detail |

### How much does it cost?

| Event | Price | Per 1,000 |
|---|---|---|
| Page checked (crawled, with every link on it tested) | $0.001 | **$1.00** |

Plus a $0.00005 start fee per run. Result rows are free: you pay for the crawl, not for how many problems are found, so a badly broken site costs no more than a clean one.

Examples: a 50-page small-business site costs about **$0.05**; a 1,000-page blog costs about **$1**; a monthly check of a 10,000-page shop costs about **$10**. Links to other sites are checked but never crawled, so they add nothing to the bill. Set **Maximum pages** to cap your cost.

**Volume discounts on higher Apify plans.** The prices above are for the Apify Free plan. On paid plans the per-page price drops automatically: about 15% lower on Bronze, 25% lower on Silver and 38% lower on Gold and above.

### Use it via API, Make, Zapier, n8n or an AI agent

**Apify API.** Start a run and get the results back in one HTTP request (replace `YOUR_API_TOKEN` with the token from Apify Console > Settings > Integrations):

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

For larger sites, start the run asynchronously and read the dataset when it finishes. Official `apify-client` libraries exist for Python and JavaScript; the **API** tab on this page has ready-made code.

**No-code automation.** Connect the tool to **Make, Zapier, n8n, Google Sheets, Slack, Airtable** or any webhook with Apify integrations, and use **Schedules** in Apify Console to check your site weekly and get the broken links in Slack or email.

**AI agents (MCP).** Give Claude, ChatGPT, Cursor, VS Code or any MCP-compatible agent direct access to this tool through the hosted Apify MCP server. Add this server URL to your client:

```
https://mcp.apify.com?tools=plotpointtech/broken-link-checker
```

### FAQ

**Is it legal to check links on a website?**
Yes, for public pages. The tool reads only publicly available pages, never logs in, respects robots.txt and spaces out its requests. Check sites you own or are authorised to audit, and follow their terms.

**Why is a link marked "restricted" when it works in my browser?**
Some sites (LinkedIn, sites behind Cloudflare challenges, some shops) refuse automated requests with 401, 403, 429 or a bot challenge. These are reported with `medium` severity and an explanation so you can verify them by hand instead of being told they are broken.

**Why are some links "skipped"?**
If a site's robots.txt disallows a URL, the tool does not request it. Skipped links appear only when **Only report problems** is off.

**Does it render JavaScript?**
No. Pages are read as HTML, which is how search engines first see links. Links added only by JavaScript after the page loads are not found.

**Does it crawl other websites?**
No. Only pages on the start URL's domain (with or without `www.`) are crawled. Links to other sites are checked with a single request each. Subdomains such as `blog.example.com` are treated as other sites.

**How is this priced compared with per-link checkers?**
Per-link pricing charges for every link tested, so a typical page with 50 to 150 links costs 50 to 150 times the per-link rate. Here a page costs $0.001 no matter how many links it has.

### Related tools from Plot Point Technologies

- [SEO Audit Crawler](https://apify.com/plotpointtech/sitemap-seo-page-audit): titles, meta descriptions, H1s, canonicals and status codes for every page in a sitemap.
- [PageSpeed Insights & Core Web Vitals Checker](https://apify.com/plotpointtech/bulk-pagespeed-lighthouse): Lighthouse performance scores for many URLs.
- [Website Tech Stack Detector](https://apify.com/plotpointtech/website-technology-detector): CMS, analytics and 290+ technologies behind a site.
- [Website Screenshot & PDF API](https://apify.com/plotpointtech/website-screenshot-pdf-generator): full-page and mobile screenshots or PDFs.
- [Website to Markdown Crawler](https://apify.com/plotpointtech/website-to-markdown-crawler): turn a whole site into clean Markdown for AI and RAG.

Plot Point Technologies is not affiliated with crawler-test.com, any website you check, or Apify.

***

If this tool saved you time, we would be grateful for a short review on this page; it helps other people find it. If something did not work as expected, please open an issue on the **Issues** tab and we will look into it quickly.

# Actor input Schema

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

Home page (or a section) of each website to crawl, e.g. https://www.example.com/. Pages on the same domain are crawled; links to other sites are checked but not crawled.

## `maxPages` (type: `integer`):

Stop after this many pages per website. You pay per page crawled, so this is also your cost limit (pages x price).

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

How many clicks away from the start URL to follow. 0 = only the start page. Pages from the sitemap count as depth 1.

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

On: one record per broken or blocked link (and redirects if turned on below). Off: one record per link found, including working ones.

## `includeRedirects` (type: `boolean`):

Add links that redirect (301/302/307/308) even when the final page works, with the full redirect chain. Useful for cleaning up old URLs and redirect chains.

## `checkExternal` (type: `boolean`):

Also check links, images, scripts and stylesheets hosted on other domains. They are only checked, never crawled.

## `checkAssets` (type: `boolean`):

Check <img>, <script src> and stylesheet files, not only <a href> links.

## `useSitemap` (type: `boolean`):

Also crawl pages listed in the site's XML sitemaps (from robots.txt or /sitemap.xml), so pages that nothing links to are checked too.

## `includePatterns` (type: `array`):

Optional. Only crawl pages whose URL matches one of these regular expressions or \* wildcards, e.g. /blog/ or */docs/*. The start URL is always crawled. Links on crawled pages are still all checked.

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

Optional. Skip crawling pages whose URL matches one of these patterns, e.g. /tag/ or ?page=. Links pointing to them are still checked.

## `maxConcurrencyPerHost` (type: `integer`):

How many requests may run at the same time against any one server. Keep this low to be polite to the website.

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

How many pages are processed at the same time.

## `timeoutSecs` (type: `integer`):

A link that does not answer in this time is reported as a timeout.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://crawler-test.com/"
    }
  ],
  "maxPages": 5,
  "maxDepth": 3,
  "onlyBroken": true,
  "includeRedirects": false,
  "checkExternal": true,
  "checkAssets": true,
  "useSitemap": true,
  "includePatterns": [],
  "excludePatterns": [],
  "maxConcurrencyPerHost": 4,
  "maxConcurrency": 5,
  "timeoutSecs": 15
}
```

# 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 = {
    "startUrls": [
        {
            "url": "https://crawler-test.com/"
        }
    ],
    "maxPages": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("plotpointtech/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": [{ "url": "https://crawler-test.com/" }],
    "maxPages": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("plotpointtech/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": [
    {
      "url": "https://crawler-test.com/"
    }
  ],
  "maxPages": 5
}' |
apify call plotpointtech/broken-link-checker --silent --output-dataset

```

## MCP server setup

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