# Broken Link Checker: Find Dead Links & 404s on Any Website (`globose_talent_mn9/broken-link-checker`) Actor

Crawl a website and check every internal and external link, image, script and stylesheet. Finds 404s, 5xx errors, dead domains, timeouts and redirect chains, with the pages and anchor text where each link appears. $0.50 per 1,000 links.

- **URL**: https://apify.com/globose_talent_mn9/broken-link-checker.md
- **Developed by:** [Andrew Shamah](https://apify.com/globose_talent_mn9) (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.50 / 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 dead links, 404s and redirect chains on any website

Crawl a website and **check every link on it**: internal pages, outbound links, images, scripts, stylesheets and iframes. Get a clean table of **broken links (404, 410, dead domains), server errors (5xx), timeouts and redirects**, with the **pages where each link appears** and its **anchor text**, so you know exactly what to fix. No browser, no login, no proxies: fast, plain HTTP checks.

**Price:** **$0.50 per 1,000 links checked** ($0.0005 per link) plus a tiny start fee. Crawling pages is free; you only pay for unique links checked. Invalid inputs are free error rows.

### What it finds

| Result | Meaning |
|---|---|
| `broken` | 404, 410 or other 4xx, unknown domain, refused connection, malformed URL |
| `server-error` | 5xx responses |
| `timeout` | No response within 20 seconds |
| `restricted` | 401, 403, 429, 999 (the server blocks automated checks, e.g. LinkedIn; usually not really broken) |
| `ok` | 2xx/3xx after following redirects (each redirect hop is listed in `redirectChain`) |
| `skipped` | Link points to a private/local network address |

### Features

- 🕸️ **Whole-site crawl** (breadth first) with page and depth limits, include/exclude URL patterns and optional subdomains.
- 🔗 **Every link type:** `<a>` links, images, scripts, stylesheets and iframes (turn assets off with `checkResources: false`).
- 🌍 **External links too:** check outbound links (on by default), with at most 2 parallel requests per host so you never hammer anybody.
- 📍 **Where to fix it:** each link lists up to 10 pages that contain it, how many times it was found, and its anchor texts.
- ↪️ **Redirect audit:** full redirect chain for every link; optionally report all redirected links as problems for SEO clean-ups.
- 🎯 **Only problems mode:** save just the broken links for a short to-do list.
- 🤖 Respects `robots.txt` and crawl-delay while crawling; HEAD first, GET fallback, so checks are light.
- 📊 A per-site **REPORT** (key-value store) with counts by result.
- ⏱️ Bulk: check many websites in one run (`startUrls` or a pasted list).

### Input examples

Check a whole site (up to 100 pages and 2,000 links):

```json
{ "startUrls": ["https://example.com"] }
```

Only broken links of the blog, internal links only:

```json
{ "startUrls": ["https://example.com/blog/"], "includePatterns": ["/blog/*"], "checkExternalLinks": false, "onlyProblems": true }
```

Quick check of the links on a few pages (no crawling beyond the start pages):

```json
{ "startUrls": ["https://example.com", "https://example.org/pricing"], "maxDepth": 0 }
```

### Output

One row per unique link:

| Field | Description |
|---|---|
| `site`, `url` | Website and the checked link |
| `status`, `statusCode`, `isBroken` | Result (see table above), HTTP status, true for broken/server-error |
| `error` | Network error, e.g. DNS failure or timeout |
| `finalUrl`, `redirected`, `redirectChain` | Where the link ends up and each hop (`301 https://...`) |
| `linkType` | `internal`, `external` or `invalid` |
| `resourceType` | `link`, `image`, `script`, `stylesheet`, `iframe` |
| `foundOnCount`, `foundOn`, `anchorTexts` | How often, on which pages and with what text the link appears |
| `contentType`, `responseTimeMs`, `checkedAt` | Extra details |

Example row:

```json
{
  "site": "example.com", "url": "https://example.com/old-page", "status": "broken", "statusCode": 404, "isBroken": true,
  "linkType": "internal", "resourceType": "link", "foundOnCount": 3,
  "foundOn": ["https://example.com/", "https://example.com/blog/post-1"], "anchorTexts": ["Read more"],
  "redirectChain": [], "finalUrl": "https://example.com/old-page", "responseTimeMs": 112
}
```

### Cost examples

- 500-link small business site: **$0.25**
- 2,000 links (default cap per site): **$1.00**
- Set **Max links** or a maximum cost per run in the run options to stay within any budget; the Actor stops cleanly when the limit is reached.

### FAQ

**Why is a link "restricted" and not broken?** Some sites (LinkedIn, Cloudflare-protected pages, rate-limited APIs) refuse automated requests with 403/429/999 even though the page works in a browser. They are reported separately so they don't pollute your broken list.

**Does it render JavaScript?** No. It reads the HTML your server sends, which is what search engines see first. Links injected only by JavaScript are not found.

**Will it overload my site?** No. Crawling uses up to 5 parallel requests (configurable) and honours crawl-delay; link checks are capped at 2 parallel requests per host.

**Is it legal?** It requests public pages exactly like a browser or search engine would, and only reads link targets' status codes. Only check sites you are allowed to crawl.

### Related Actors

#### SEO & web suite

- [SEO Audit Crawler](https://apify.com/globose_talent_mn9/seo-audit-crawler)
- [Sitemap URL Extractor](https://apify.com/globose_talent_mn9/sitemap-urls)
- [Bulk Redirect Checker](https://apify.com/globose_talent_mn9/redirect-checker)
- [Website Metadata / Open Graph Extractor](https://apify.com/globose_talent_mn9/website-metadata-extractor)
- [Website Screenshot](https://apify.com/globose_talent_mn9/website-screenshot)
- [Website Image Extractor](https://apify.com/globose_talent_mn9/website-image-extractor)
- [SSL Certificate Checker](https://apify.com/globose_talent_mn9/ssl-certificate-checker)
- [Subdomain Finder](https://apify.com/globose_talent_mn9/subdomain-finder)
- [DNS & Email Security Checker (SPF/DKIM/DMARC)](https://apify.com/globose_talent_mn9/dns-email-security-checker)
- [WHOIS Domain Lookup](https://apify.com/globose_talent_mn9/whois-domain-lookup)
- [Domain Availability Checker](https://apify.com/globose_talent_mn9/domain-availability-rdap)
- [Tech Stack Detector](https://apify.com/globose_talent_mn9/tech-stack-detector)

#### Documents suite

- [PDF Text Extractor](https://apify.com/globose_talent_mn9/pdf-text-extractor)
- [Scanned PDF & Image OCR](https://apify.com/globose_talent_mn9/pdf-image-ocr)
- [Article Extractor](https://apify.com/globose_talent_mn9/article-extractor)
- [URL & HTML to PDF Converter](https://apify.com/globose_talent_mn9/url-to-pdf)

#### Jobs suite

- [Greenhouse Jobs API](https://apify.com/globose_talent_mn9/greenhouse-jobs-api)
- [Lever Jobs API](https://apify.com/globose_talent_mn9/lever-jobs-api)
- [Ashby Jobs API](https://apify.com/globose_talent_mn9/ashby-jobs-api)
- [Workday Jobs API](https://apify.com/globose_talent_mn9/workday-jobs-api)
- [Company Jobs API (10 ATS)](https://apify.com/globose_talent_mn9/ats-jobs-api)
- [Remote Jobs Aggregator](https://apify.com/globose_talent_mn9/remote-jobs-aggregator)

#### Also by us

- [Wayback Machine Snapshots](https://apify.com/globose_talent_mn9/wayback-machine-snapshots)
- [RSS Feed Reader](https://apify.com/globose_talent_mn9/rss-feed-reader)
- [Website Contact Details Scraper](https://apify.com/globose_talent_mn9/website-contact-details-scraper)

# Actor input Schema

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

One website or start page per line, e.g. https://example.com. The Actor crawls each site and checks every link it finds.

## `startUrlsText` (type: `string`):

Paste many websites separated by new lines, spaces or commas.

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

How many pages of each site to scan for links. Pages are free; you pay per link checked.

## `maxLinksPerSite` (type: `integer`):

Unique links (URLs) to check on each site.

## `maxLinksTotal` (type: `integer`):

0 = no limit.

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

How many clicks away from the start page to crawl. 0 = check only the links on the start pages.

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

Also check links to other websites (outbound links).

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

Find broken images and assets, not only <a> links.

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

Also crawl pages on blog.example.com, docs.example.com and so on.

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

Optional. Only crawl pages whose URL contains one of these patterns (\* wildcard or /regex/), e.g. /docs/\*.

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

Optional. Pages to skip when crawling (their links are still checked if found elsewhere).

## `skipLinksMatching` (type: `array`):

Optional. Links to ignore entirely, e.g. linkedin.com or /cdn-cgi/.

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

Skip pages disallowed by robots.txt (and honour crawl-delay).

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

Save only broken, server-error and timed-out links (plus redirects if enabled below). Every checked link is still charged.

## `reportRedirects` (type: `boolean`):

With 'Only save problem links', also save links that redirect (useful for SEO clean-ups).

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

Parallel requests while crawling the site.

## `linkConcurrency` (type: `integer`):

Parallel link checks (at most 2 at a time per host).

## Actor input object example

```json
{
  "startUrls": [
    "https://crawlee.dev"
  ],
  "maxPagesPerSite": 3,
  "maxLinksPerSite": 30,
  "maxLinksTotal": 0,
  "maxDepth": 10,
  "checkExternalLinks": true,
  "checkResources": true,
  "includeSubdomains": false,
  "respectRobotsTxt": true,
  "onlyProblems": false,
  "reportRedirects": false,
  "maxConcurrency": 5,
  "linkConcurrency": 10
}
```

# Actor output Schema

## `overview` (type: `string`):

Every checked link with its result.

## `report` (type: `string`):

Per-site counts by result.

# 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": 3,
    "maxLinksPerSite": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("globose_talent_mn9/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": 3,
    "maxLinksPerSite": 30,
}

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

```

## MCP server setup

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