# HTTP Redirect Chain & Status Checker (`thomson-digital/http-redirect-checker`) Actor

Bulk-check HTTP status codes and the full redirect chain for any URL list. Records every hop (status + Location), final URL, hop count, timing, and flags broken/dead links (4xx/5xx/timeouts). Batch from a URL list, CSV-like paste, or XML sitemap. Fast, monitor-friendly JSON — no browser needed.

- **URL**: https://apify.com/thomson-digital/http-redirect-checker.md
- **Developed by:** [Matt](https://apify.com/thomson-digital) (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

$0.80 / 1,000 checked urls

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

## HTTP Redirect Chain & Status Checker

Bulk-check **HTTP status codes** and the **full redirect chain** for any list of URLs. For every URL you get each hop (status + `Location`), the final URL, hop count, timing, and clear **broken / dead** flags for 4xx, 5xx, timeouts and network errors.

Paste a URL list, a CSV-like dump, or point at an **XML sitemap** — no browser, no login, monitor-friendly flat JSON. Schedule it to catch new 404s after deploys or track whether marketing short-links still resolve.

### What does this Actor do?

- ✅ **Status check** every URL (HEAD by default, auto-falls back to GET when servers reject HEAD)
- 🔗 **Full redirect chain**: every hop records `url`, `statusCode`, `location`, `elapsedMs`
- 🏁 **Final URL + hop count + total time** for monitoring and SEO audits
- 💀 **Broken / dead detection**: 4xx, 5xx, timeouts, SSL and network errors (`isBroken`, `errorType`)
- 📦 **Batch inputs**: URL list, CSV-like paste, or XML sitemap / sitemap index
- 🎯 **Filters**: only broken, only redirects, include/exclude regex
- 🛡️ Retries with backoff on 429/5xx; concurrency capped for Free-plan friendliness
- 🤖 AI-agent friendly: simple input, flat JSON, usable via Apify API and MCP

### Why use a redirect-chain checker?

A single final status code hides the story. Marketing links, HTTP→HTTPS upgrades, trailing-slash rules and CDN hops all rewrite the URL. This Actor keeps the **hop-by-hop trail** so SEO, QA and monitoring tools can see exactly where a chain breaks or loops — not just that it ended on a 404.

### What data can it extract?

| Field | Description |
| --- | --- |
| `url` | Original input URL |
| `finalUrl` | URL after following redirects |
| `finalStatusCode` | Final HTTP status |
| `ok` | `true` when final status is 2xx |
| `isRedirect` | At least one hop / URL changed |
| `isBroken` | 4xx/5xx, timeout, or network/SSL error |
| `hopCount` | Number of redirect hops |
| `redirectChain` | Array of hops: `url`, `statusCode`, `location`, `elapsedMs` |
| `totalTimeMs` | Wall-clock time for the whole chain |
| `errorType` | `timeout` / `network` / `ssl` / `too_many_redirects` / `other` |
| `contentType`, `server`, … | Optional final-response headers |

### How to check redirects and broken links

1. Open the **Input** tab and paste URLs (defaults already include a few public examples).
2. Optionally add a sitemap URL and set **Max URLs**.
3. Click **Start**. Results appear in the **Dataset** within seconds.
4. For monitoring: create an Apify **Schedule** and filter on `isBroken=true` (or enable **Only output broken / dead URLs**).

### How much does it cost?

Pay per event: you are charged for each URL row written to the dataset. Sitemap discovery and filtered-out rows are not charged. **Platform usage is covered by the Actor** — customers do not pay compute on top. Set a maximum cost per run in the run options; the Actor stops cleanly when it is reached.

Typical smoke tests of a handful of URLs finish in well under a minute on 256 MB.

### Input

`urls` and/or `sitemapUrls` — at least one is required. Example:

```json
{
  "urls": [
    "https://example.com",
    "https://httpbin.org/redirect/2",
    "https://httpbin.org/redirect-to?url=https://example.com&status_code=301",
    "https://httpbin.org/status/404"
  ],
  "maxUrls": 20,
  "requestMethod": "HEAD",
  "maxRedirects": 15,
  "onlyBroken": false,
  "maxConcurrency": 5
}
```

| Field | Description |
| --- | --- |
| `urls` | URL list / CSV-like paste. |
| `sitemapUrls` | Optional XML sitemaps to expand into page URLs. |
| `maxUrls` | Cap after de-duplication (default 100). |
| `requestMethod` | `HEAD` (default) or `GET`. |
| `maxRedirects` | Hop limit / loop protection (default 15). |
| `onlyBroken` / `onlyRedirects` | Output filters. |
| `includeUrlPatterns` / `excludeUrlPatterns` | Regex filters on input URLs. |
| Advanced | `maxConcurrency`, `requestTimeoutSecs`, `maxRetries`, `proxyConfiguration`. |

See the **Input** tab for the full form.

### Output example

```json
{
  "url": "https://httpbin.org/redirect-to?url=https://example.com&status_code=301",
  "finalUrl": "https://example.com",
  "finalStatusCode": 200,
  "ok": true,
  "isRedirect": true,
  "isBroken": false,
  "hopCount": 1,
  "redirectChain": [
    {
      "url": "https://httpbin.org/redirect-to?url=https://example.com&status_code=301",
      "statusCode": 301,
      "location": "https://example.com",
      "elapsedMs": 48.2
    },
    {
      "url": "https://example.com",
      "statusCode": 200,
      "location": null,
      "elapsedMs": 95.0
    }
  ],
  "totalTimeMs": 145.1,
  "method": "HEAD",
  "source": "list"
}
```

A `SUMMARY` record in the key-value store holds aggregate counts (`okCount`, `redirectCount`, `brokenCount`, `timeoutCount`).

### Tips for large batches

- Start with `maxUrls` small, then raise it once the sample looks right.
- Keep `maxConcurrency` around 5–10 on the Free plan.
- Prefer `HEAD` unless a site blocks it.
- Leave Apify Proxy off unless targets block datacenter IPs — proxies spend credits.

### FAQ

**Does it execute JavaScript / open a browser?**\
No. It uses plain HTTP requests, so it is fast and cheap. Client-side redirects are not followed.

**Will it follow meta-refresh or JavaScript redirects?**\
Only HTTP 3xx `Location` redirects. Meta-refresh and JS navigations are out of scope.

**How are redirect loops handled?**\
The Actor stops when a URL repeats in the chain or `maxRedirects` is hit, and sets `errorType` to `too_many_redirects`.

**Can I feed a sitemap?**\
Yes — put sitemap or sitemap-index URLs in `sitemapUrls`. Nested indexes are walked (depth-limited).

### Support

Built by **thomson-digital**. Open an issue on the Actor page if something looks wrong — include a sample URL and the run ID.

# Actor input Schema

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

One URL per line. Paste absolute http(s) URLs, or a CSV-like list (commas/newlines are fine). Each URL is checked for status code and the full redirect chain.

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

Optional. Fetch these XML sitemaps (or sitemap indexes) and check every <loc> URL found. Combined with the URLs list above. Keep maxUrls small for testing.

## `maxUrls` (type: `integer`):

Hard cap on how many URLs are checked in this run (after de-duplication). Keep low for smoke tests; raise for bulk audits.

## `requestMethod` (type: `string`):

HEAD is faster and enough for most status/redirect checks. GET is used automatically when a server rejects HEAD (405/403/501). Choose GET if you need response body size / content-type from the final hop.

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

Stop following redirects after this many hops (loop / chain protection).

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

When enabled, only write rows that are broken (4xx/5xx), timed out, or hit a network error. Healthy 2xx/3xx finals are skipped.

## `onlyRedirects` (type: `boolean`):

When enabled, only write rows where hopCount >= 1 (or final URL differs from the start URL).

## `includeUrlPatterns` (type: `array`):

Optional. Keep only input URLs that match at least one regular expression.

## `excludeUrlPatterns` (type: `array`):

Optional. Drop input URLs that match any of these regular expressions.

## `saveResponseHeaders` (type: `boolean`):

When enabled, include contentType, contentLength, server and cacheControl from the final response.

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

How many URLs to check in parallel. Keep modest on the Free plan (default 5) to avoid rate limits and credit spikes.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each hop request. Timeouts are recorded as broken with errorType=timeout.

## `maxRetries` (type: `integer`):

Retries for 429/5xx and transport errors on a single hop (not for following redirects).

## `proxyConfiguration` (type: `object`):

Optional. Most public URLs work without a proxy. Use Apify Proxy only if targets block datacenter IPs. Residential / higher tiers spend Free-plan credits fast — leave off unless needed.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://httpbin.org/redirect/2",
    "https://httpbin.org/redirect-to?url=https://example.com&status_code=301",
    "https://httpbin.org/status/404"
  ],
  "sitemapUrls": [],
  "maxUrls": 20,
  "requestMethod": "HEAD",
  "maxRedirects": 15,
  "onlyBroken": false,
  "onlyRedirects": false,
  "includeUrlPatterns": [],
  "excludeUrlPatterns": [],
  "saveResponseHeaders": true,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 20,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset of status / redirect-chain results

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

Key-value store record with totals and broken-link counts

# 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": [
        "https://example.com",
        "https://httpbin.org/redirect/2",
        "https://httpbin.org/redirect-to?url=https://example.com&status_code=301",
        "https://httpbin.org/status/404"
    ],
    "maxUrls": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("thomson-digital/http-redirect-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": [
        "https://example.com",
        "https://httpbin.org/redirect/2",
        "https://httpbin.org/redirect-to?url=https://example.com&status_code=301",
        "https://httpbin.org/status/404",
    ],
    "maxUrls": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("thomson-digital/http-redirect-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": [
    "https://example.com",
    "https://httpbin.org/redirect/2",
    "https://httpbin.org/redirect-to?url=https://example.com&status_code=301",
    "https://httpbin.org/status/404"
  ],
  "maxUrls": 20
}' |
apify call thomson-digital/http-redirect-checker --silent --output-dataset

```

## MCP server setup

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