# Broken Link Checker & SEO Crawler: 404s, Images, Redirects (`manageable_gully/broken-link-checker`) Actor

Crawl a website and find every broken link (404s), dead external link, missing image, script or stylesheet, with the pages they appear on and the anchor text. Respects robots.txt. Priced per page crawled, not per link: $2 per 1,000 pages.

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

## Pricing

from $2.00 / 1,000 crawled pages

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, Broken Images & Redirects

Crawls your website and lists every **broken link, missing image, dead script or stylesheet and dead external link**, each with **the pages it appears on** and its anchor text, so you know exactly what to fix.

**Priced per page crawled, not per link.** A typical page has 50–150 links, so this costs far less than per-link checkers.

### What you can use it for

- **SEO cleanup:** find every internal 404 and dead external link before Google does, with the exact page and anchor text to fix.
- **Website migrations:** crawl the new site after a redesign or CMS move and catch links that still point to old URLs.
- **Agencies:** run a link audit for every client site on a monthly schedule and send the CSV to the content team.
- **Content teams and blogs:** find outbound links that rotted over the years (404, DNS errors, timeouts).
- **QA before launch:** check that images, scripts, stylesheets and iframes all load.

### How to use it

1. Add your site under **Start URLs** (you can add several sites; each is crawled separately).
2. Set **Max pages per site** to cap the crawl and the cost.
3. Click **Start**.
4. Open the results: one row per broken or blocked URL, with `foundOn` pages. Export to CSV or Excel.

### Features

- Stays on your domain (optionally includes subdomains) and follows internal links up to a depth limit.
- Checks `<a>` links, `<img>`, `<script>`, stylesheets, icons, `<iframe>`, `<video>`/`<audio>` sources, and external links.
- Verdicts: **broken** (4xx/5xx, DNS error, timeout), **blocked** (401/403/429: the server refused the checker, so the link may still work in a browser) and **ok**.
- Sends a HEAD request first and confirms with GET, which avoids false 404s from servers that mishandle HEAD. Each URL is checked only once per run.
- **Polite by design:** always respects robots.txt, allows at most 2 parallel requests per external host, and backs off on 429.
- Writes a summary record to the key-value store (`SUMMARY`): pages crawled, links checked, broken, blocked.

### Input

```json
{ "startUrls": [{"url": "https://example.com"}], "maxPagesPerSite": 200, "checkExternalLinks": true, "checkResources": true }
```

| Field | Default | Meaning |
|---|---|---|
| `startUrls` | – | One or more sites (each is crawled separately) |
| `maxPagesPerSite` | 200 | Upper limit on pages crawled, and so on cost |
| `checkExternalLinks` | true | Verify links to other domains |
| `checkResources` | true | Verify images, scripts, CSS, iframes and media |
| `includeWorkingLinks` | false | Also output working links |
| `includeSubdomains` | false | Treat `blog.example.com` as internal |
| `maxDepth` / `maxConcurrency` / `timeoutSecs` | 10 / 5 / 15 | Advanced |

### Output (one item per broken or blocked URL)

```json
{
  "verdict": "broken", "status": 404, "url": "https://example.com/old-pricing",
  "resourceType": "link", "internal": true,
  "foundOn": ["https://example.com/", "https://example.com/blog/launch"],
  "anchorTexts": ["See pricing"], "error": null, "site": "https://example.com/"
}
```

Export as CSV or Excel and hand it to whoever edits the site, or schedule a weekly run and get notified only when `broken > 0`.

### Pricing

Pay per event, no monthly rent: **$0.002 per page crawled** (**$2.00 per 1,000**).

| Example | Cost |
|---|---|
| 200 pages (a small site) | $0.40 |
| 1,000 pages | $2.00 |
| 10,000 pages | $20.00 |

You can set a **maximum cost per run** in the run options; the Actor stops cleanly when it is reached. New to Apify? The free plan includes $5 of platform credit every month, so you can try this Actor at no cost.

### API, integrations and AI agents (MCP)

Run it from your own code with the [Apify API](https://docs.apify.com/api/v2) and get the results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/manageable_gully~broken-link-checker/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" -d @input.json
```

```python
from apify_client import ApifyClient
run = ApifyClient("<YOUR_APIFY_TOKEN>").actor("manageable_gully/broken-link-checker").call(run_input={...})
```

- **No-code:** use the Apify app in **n8n, Make or Zapier** ("Run Actor", then "Get dataset items"), or send results to Google Sheets, Slack or a webhook.
- **AI agents (MCP):** add `https://mcp.apify.com?tools=manageable_gully/broken-link-checker` to Claude, Cursor, VS Code or any MCP client and the agent can call this Actor as a tool.
- **Schedules:** run it hourly, daily or weekly from Apify Console.

### FAQ

**Is it priced per link?** No. You pay per page crawled ($0.002). All links and resources on that page are checked at no extra cost, so a page with 150 links still costs $0.002.

**Can it check a list of URLs without crawling?** Set `maxDepth` to 0 to check only the links found on your start pages.

**Why "blocked" instead of "broken"?** Sites such as LinkedIn, Amazon and GitHub often refuse automated checkers (403/429). Those links usually work for people, so they are listed separately to avoid false alarms.

**Does it run JavaScript?** No. It reads server-rendered HTML, which is fast and cheap. Links that only appear after client-side JS runs are not discovered.

**Can I check someone else's site?** Only public pages, and only what robots.txt allows. The Actor never logs in or submits forms.

**Can AI agents use it?** Yes. It is available as a tool through the Apify MCP server (`https://mcp.apify.com?tools=manageable_gully/broken-link-checker`) and the Apify API, and it returns structured JSON that agents can read directly.

### More tools from WebIntel Tools

- [SEO Audit & Domain Checker](https://apify.com/manageable_gully/website-health-audit): SEO, DNS, SSL and security-header audit for lists of domains
- [Lighthouse & PageSpeed Bulk Audit](https://apify.com/manageable_gully/lighthouse-bulk-audit): Lighthouse scores and Core Web Vitals for hundreds of URLs
- [Web Page to Markdown](https://apify.com/manageable_gully/page-to-markdown): clean Markdown and RAG chunks from any URL, for LLMs
- [Website Tech Stack Detector](https://apify.com/manageable_gully/website-tech-detector): BuiltWith/Wappalyzer-style tech stack lookup in bulk

See [all WebIntel Tools Actors](https://apify.com/manageable_gully).

*Made by WebIntel Tools. This Actor was built and is maintained with AI assistance. Report issues on the Issues tab; they are monitored daily.*

# Actor input Schema

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

Homepage (or any page) of each site to check. The crawler stays on the same domain.

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

Stop after this many HTML pages per site. You are charged per page crawled.

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

Also verify links pointing to other websites (each URL is checked once).

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

Verify <img>, <script>, \<link rel=stylesheet/icon>, <iframe> and media sources, not only <a> links.

## `includeWorkingLinks` (type: `boolean`):

Off = only broken and blocked links (smaller dataset). On = every checked URL.

## `includeSubdomains` (type: `boolean`):

Crawl blog.example.com when starting from example.com.

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

Clicks away from the start URL.

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

Parallel page fetches. Keep low to be gentle on the site.

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

How long to wait for each HTTP request before treating the link as timed out.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://crawlee.dev"
    }
  ],
  "maxPagesPerSite": 200,
  "checkExternalLinks": true,
  "checkResources": true,
  "includeWorkingLinks": false,
  "includeSubdomains": false,
  "maxDepth": 10,
  "maxConcurrency": 5,
  "timeoutSecs": 15
}
```

# Actor output Schema

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

One item per broken, blocked or failing link/resource, with HTTP status and the pages it appears on.

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

Per-site crawl summary (pages crawled, links checked, broken count).

# 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://crawlee.dev"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("manageable_gully/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://crawlee.dev" }] }

# Run the Actor and wait for it to finish
run = client.actor("manageable_gully/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://crawlee.dev"
    }
  ]
}' |
apify call manageable_gully/broken-link-checker --silent --output-dataset

```

## MCP server setup

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