# Broken Link Checker: Bulk URL Status & Redirect Chains (`wintersworks/url-status-link-checker`) Actor

Input: a list of URLs, or a site to crawl. Output: broken link checker results with HTTP status, full redirect chain and, in crawl mode, every broken or redirected link with source page and anchor text. $0.50 per 1,000 URLs. No browser.

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

## Pricing

$0.50 / 1,000 url 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: Bulk URL Status & Redirect Chains

A fast bulk HTTP status checker, redirect checker and broken link checker. Paste a list of URLs to get the final status code, full redirect chain, response time and headers for each, or give it a start URL and it crawls the site and reports every broken (404) and redirected link with the pages it appears on and its anchor text. Useful for SEO migration redirect audits, 404 finding, link rot cleanup and uptime spot checks. HTTP only, no browser, so it is cheap: $0.50 per 1,000 URLs.

### Two modes

**1. URL list (`urls`)**: for each URL you get final status, every redirect hop (URL and status), final URL, response time, content-type, content-length, and for HTML pages the canonical URL, meta robots, title and X-Robots-Tag header. Failures are classified: `DNS`, `TIMEOUT`, `TLS`, `CONNECTION`, `TOO_MANY_REDIRECTS`, `REDIRECT_LOOP`.

**2. Broken link crawl (`crawlStartUrls` + `maxPages`)**: crawls same-site pages (respects robots.txt, polite: 3 requests at a time per host), collects every internal and external link, checks each unique link once (HEAD, falling back to GET), and outputs one row per problem link with `sourcePages` and `anchorText`. Set `onlyProblems` to false to also output healthy links.

### Use cases

- SEO migration redirect audit: verify old URLs 301 to the right place with no chains or loops.
- Find 404s and broken outbound links on your site or a client's site.
- Check redirect chains (http to https, www to non-www, trailing slashes).
- Spot-check lists of URLs from a sitemap, CRM or backlink export.

### Input

```json
{ "urls": ["http://apify.com", "https://example.com", "https://httpbin.org/status/404"], "concurrency": 10, "timeoutSecs": 15, "maxRedirects": 10 }
```

Crawl mode:

```json
{ "crawlStartUrls": ["https://example.com"], "maxPages": 50, "maxLinks": 500, "onlyProblems": true }
```

### Output

```json
{ "url": "http://apify.com/", "status": 200, "finalUrl": "https://apify.com/", "redirectCount": 1,
  "redirectChain": [{"url":"http://apify.com/","status":301},{"url":"https://apify.com/","status":200}],
  "responseTimeMs": 408, "contentType": "text/html; charset=utf-8", "canonical": "https://apify.com/", "metaRobots": "index,follow", "errorType": null }
```

Crawl mode row:

```json
{ "url": "https://example.com/old", "status": 404, "problem": "broken", "sourcePages": ["https://example.com/"], "anchorText": "Old page" }
```

### Example output

Real output from a default run (some fields omitted for width):

| url | status | finalUrl | redirectCount | responseTimeMs |
|---|---|---|---|---|
| https://httpbin.org/status/404 | 404 | https://httpbin.org/status/404 | 0 | 63 |
| https://example.com/ | 200 | https://example.com/ | 0 | 116 |

Every run also produces a ready-made table view in the Output tab, and you can export to JSON, CSV or Excel.

### Pricing

Pay per event: **$0.0005 per URL checked** ($0.50 per 1,000). In crawl mode you pay per unique link checked (deduplicated across pages), not for the pages crawled. The run stops cleanly at your spending limit.

### Limitations

- HTTP and HTTPS only. No JavaScript rendering, so links injected by scripts and JS redirects are not seen; only HTTP redirects (up to 10 by default, max 20) are followed and recorded.
- Defaults: 20 crawled pages (max 1,000), 500 unique links checked (max 20,000), 15 s timeout per request (3 to 60 s), 10 checks in parallel (max 50). Crawling stays on the start site and checks at most 3 links per host at a time.
- Crawl mode reads only the first 500 KB of each page and skips files such as PDFs, images, CSS and JS for crawling. `robots.txt` Disallow rules are honored for pages it crawls, but links found are checked with a single request each.
- Servers that block bots (403, 429, CAPTCHA, anti-bot walls) are reported as returned. The checker identifies itself honestly and does not evade blocking, so some links show false "broken" results.
- URL fragments (#) are stripped and not checked. Slow servers can be reported as TIMEOUT for a single failed check.

### FAQ

**Does it run JavaScript?** No. Links added by client-side JavaScript are not seen in crawl mode, and JS redirects are not followed; only HTTP redirects are.
**Are failed URLs charged?** Yes, a DNS error or timeout is a valid check result and is charged like any other URL.
**Some sites return 403/429 to bots.** Those are reported as is; the checker identifies itself honestly and does not evade blocking.
**Are fragments (#) checked?** No, they are stripped.
**Is robots.txt respected?** In crawl mode, yes for pages crawled. Link status checks of discovered URLs use a single request each.

**Is this legal?** Checking the status of public URLs is ordinary web activity, much like a browser or search crawler. The Actor identifies itself with a contact address, honors robots.txt when crawling and keeps request rates low. Crawl only sites you own or have permission to test, and follow each site's terms. You are responsible for how you use it.

Built by Winters Works.

### Use from code and AI agents

Call it from any language with the Apify API, or let an AI agent find and run it through the [Apify MCP server](https://mcp.apify.com).

```python
from apify_client import ApifyClient
run = ApifyClient("<YOUR_APIFY_TOKEN>").actor("wintersworks/url-status-link-checker").call(run_input={"urls": ["http://apify.com", "https://example.com", "https://httpbin.org/status/404"]})
items = ApifyClient("<YOUR_APIFY_TOKEN>").dataset(run["defaultDatasetId"]).list_items().items
```

Results land in the run's dataset (JSON, CSV, Excel). Set a maximum charge per run in the run options to cap spend.

# Actor input Schema

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

URLs to check, one per line. Each gets status code, redirect chain, timing and headers.

## `crawlStartUrls` (type: `array`):

Optional. Crawl same-site pages from these URLs (respecting robots.txt) and check every outgoing link. If set, results are one row per broken/redirected link with source pages and anchor text.

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

Maximum number of same-site pages to crawl per start URL set (crawl mode).

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

Cap on unique links checked in crawl mode (each is charged).

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

In crawl mode, output only broken (4xx/5xx/error) and redirected links. Unchecked links are still charged.

## `concurrency` (type: `integer`):

Parallel requests. Crawl mode also limits to 3 requests at once per host.

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

Timeout for each HTTP request.

## `maxRedirects` (type: `integer`):

Maximum redirect hops to follow before reporting TOO_MANY_REDIRECTS.

## Actor input object example

```json
{
  "urls": [
    "http://apify.com",
    "https://example.com",
    "https://httpbin.org/status/404"
  ],
  "maxPages": 20,
  "maxLinks": 500,
  "onlyProblems": true,
  "concurrency": 10,
  "timeoutSecs": 15,
  "maxRedirects": 10
}
```

# Actor output Schema

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

All result items from the run's default dataset.

# 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": [
        "http://apify.com",
        "https://example.com",
        "https://httpbin.org/status/404"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wintersworks/url-status-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": [
        "http://apify.com",
        "https://example.com",
        "https://httpbin.org/status/404",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("wintersworks/url-status-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": [
    "http://apify.com",
    "https://example.com",
    "https://httpbin.org/status/404"
  ]
}' |
apify call wintersworks/url-status-link-checker --silent --output-dataset

```

## MCP server setup

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