# Broken Link Checker - Status Codes, Redirects & Sitemaps (`tidybytetools/broken-link-checker`) Actor

Check thousands of links at once. Get the status code, redirect chain, final URL and speed of each link. Paste links, give a sitemap, or scan pages for their links. Follows robots.txt. $0.001 per link.

- **URL**: https://apify.com/tidybytetools/broken-link-checker.md
- **Developed by:** [Tidy Byte Tools](https://apify.com/tidybytetools) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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 - Status Codes, Redirects & Sitemaps

Check thousands of links at once. For every link you get the **status code** (200, 404, 500…), the full **redirect chain** and where it ends up, how **fast** it was, and simple notes like "slow" or "not https".

You can give it links three ways:

1. **Paste a list of links** (or upload a text file, one link per line).
2. **Give a sitemap link** (`sitemap.xml`). We check every page in it, sitemap index files too.
3. **Give pages to scan.** We open each page, find every link on it, and check them all. Great for finding broken links on your own site.

### What does it cost?

You pay only for what you use. No monthly fee.

| What | Price |
|---|---|
| Each link checked | **$0.001** |
| Each page scanned for links (only with "Pages to scan") | **$0.002** |
| Duplicate links | free |
| Links skipped because of robots.txt | free |
| Sitemaps or pages that could not be opened | free |

Examples:

- 1,000 links from a list or sitemap: **$1.00**
- Scan 50 pages that have 2,000 different links in total: 50 × $0.002 + 2,000 × $0.001 = **$2.10**

Apify also adds a tiny start fee for each run. You can set a **max cost per run** in Apify. We stop before going over it and tell you how many links were not checked. You are never charged for those.

### What you get

One row for each link:

| Field | What it means |
|---|---|
| `url` | The link we checked |
| `status` | The status code, like `200` or `404`. `robots` means we skipped it because the site asked bots not to open it |
| `ok` | `true` if the link works (status under 400) |
| `final_url` | Where the link ends up after redirects |
| `redirects` / `chain` | How many hops, and each hop with its code |
| `ms` / `slow` | How long it took, and if it was slower than your limit |
| `notes` | Short notes: `not https`, `slow`, `long redirect chain`, `http to https` and more |
| `error` | Plain words when it fails, like `timed out`, `redirect loop`, `no such domain` |
| `foundOn` | For scanned pages: the pages where this link was found |

You also get three files in the run's key-value store:

- `SUMMARY`: how many links were checked, broken, redirected, slow and skipped.
- `report.csv`: every link in a spreadsheet file.
- `report.md`: a short report you can read or paste into a ticket.

### Be kind to websites

- We read each site's **robots.txt** and skip links it asks bots not to open (you can turn this off for your own site).
- We wait **0.5 seconds** between requests to the same site by default. Other sites are checked at the same time, so big lists still go fast.
- We ask for headers only (a HEAD request) first. If a site refuses that, we try a normal GET.

### Handy settings

- **Only show problems:** save only broken links and links with a note. Every checked link is still charged, and the full list is in `report.csv`.
- **Which links on scanned pages:** all, only links to the same site, or only links to other sites.
- **Also check images:** add image links (`img src`) from scanned pages.
- **Flag odd-looking domains:** a warning for names like `paypa1.com` or a brand name on someone else's domain. It is a hint, not proof.
- **Max links:** stop after this many links (default 5,000).

### Example input

```json
{
  "pagesToScan": [{ "url": "https://yoursite.com/" }, { "url": "https://yoursite.com/blog/" }],
  "linkScope": "all",
  "onlyProblems": true
}
```

### Run it every week

Use **Schedules** in Apify to run it every week on your sitemap. Add a webhook or the Slack/email integration to hear about new broken links.

### For AI agents and code

Call it through the Apify API, the Apify MCP server (`mcp.apify.com`), or any Apify integration. Cost is $0.001 per link checked and $0.002 per page scanned.

### What it does not do

- It does not crawl a whole site by itself. It scans the pages you give it (or the pages in your sitemap list, if you put them in "Pages to scan").
- It does not run JavaScript. Links that only appear after JavaScript runs are not found on scanned pages.
- Some sites block all bots. Those links may show `403` even if they work in your browser.

### FAQ

**Why is a link that works in my browser marked 403?** Some sites block automated checks. Try turning on "Use full GET requests".

**Do I pay for broken links?** Yes, a broken link is still a checked link. That is the point of the tool. Duplicates and robots.txt skips are free.

**Is there a free version?** Yes. `link-check-lite` is free on [GitHub](https://github.com/tidybytetools/link-check-lite) and [PyPI](https://pypi.org/project/link-check-lite/) and runs on your own computer.

Made by Tidy Byte Tools.

# Actor input Schema

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

The links you want checked. You can also upload a text file with one link per line.

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

Links to sitemap.xml files. We check every page link in them (sitemap index files too).

## `pagesToScan` (type: `array`):

We open each page, find every link on it, and check them all. Each page costs $0.002 on top of the links.

## `linkScope` (type: `string`):

For 'Pages to scan' only.

## `includeImages` (type: `boolean`):

Also check the image links (img src) on scanned pages.

## `onlyProblems` (type: `boolean`):

Only save broken links and links with a note (redirect, slow, not https). Every checked link is still charged. The full report is in report.csv.

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

We check at most this many links per run. Keeps costs in check.

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

Skip links a site's robots.txt asks bots not to open. Skipped links are free.

## `perHostDelaySecs` (type: `string`):

Be kind to small sites. 0.5 means at most 2 requests a second to one site. Other sites are checked at the same time.

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

How long to wait for each link before calling it 'timed out'.

## `slowMs` (type: `integer`):

Links that take longer than this get a 'slow' note.

## `useGet` (type: `boolean`):

Off: we ask for headers only (HEAD), which is faster, and fall back to GET when a site refuses HEAD.

## `checkDomains` (type: `boolean`):

Adds a warning for domains that look like a trick, like paypa1.com or a brand name on a risky ending. A hint, not proof.

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

How many links we check at the same time (across different sites).

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://apify.com/this-page-does-not-exist-123"
    }
  ],
  "linkScope": "all",
  "includeImages": false,
  "onlyProblems": false,
  "maxLinks": 5000,
  "respectRobotsTxt": true,
  "perHostDelaySecs": "0.5",
  "timeoutSecs": 15,
  "slowMs": 2000,
  "useGet": false,
  "checkDomains": false,
  "maxConcurrency": 16
}
```

# Actor output Schema

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

No description

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

No description

## `reportCsv` (type: `string`):

No description

## `reportMd` (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": [
        {
            "url": "https://apify.com"
        },
        {
            "url": "https://apify.com/this-page-does-not-exist-123"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidybytetools/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": [
        { "url": "https://apify.com" },
        { "url": "https://apify.com/this-page-does-not-exist-123" },
    ] }

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

```

## MCP server setup

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