# Bulk Redirect Chain Checker & Loop Finder (`davidbenittah/redirect-chain-auditor`) Actor

Trace every hop for up to 100 URLs in one run. This redirect chain checker follows 301, 302, 303, 307 and 308 responses, flags redirect loops, 4xx and 5xx destinations and chains longer than one hop, then returns each full chain with status codes, Location targets and per-hop response times.

- **URL**: https://apify.com/davidbenittah/redirect-chain-auditor.md
- **Developed by:** [David](https://apify.com/davidbenittah) (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

from $5.00 / 1,000 url auditeds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Bulk Redirect Chain Checker & Loop Finder

Check up to 100 URLs in one run and see exactly where each one lands. This bulk redirect chain checker follows every 301, 302, 303, 307 and 308 hop, records the status code and response time of each step, and flags the three chains that cost you traffic: loops, destinations that answer 404 or 500, and links that take two or more hops to arrive.

Redirects are cheap until they are wrong. During a site migration, campaign launch, affiliate update, or domain change, one stale hop can send customers to a 404, waste crawl budget, strip trust from a campaign URL, or create a loop that browsers never escape. Checking a few links by hand is easy. Checking hundreds after every deployment is where the bill appears.

### Who uses it

- **SEO agencies:** validate redirect maps before and after client migrations without opening URLs one by one.
- **Web agencies:** catch loops and 404 destinations after deployments, CMS changes, or domain moves.
- **Growth teams:** verify campaign and affiliate links before paid traffic reaches them.
- **Ecommerce teams:** audit old product and category URLs after catalog restructuring.
- **Developers:** add a simple redirect regression check to an automation or release workflow.

### What the bulk redirect chain checker does

For every submitted public HTTP or HTTPS URL, it:

1. Follows 301, 302, 303, 307, and 308 responses manually.
2. Records the URL, status, `Location` destination, and response time for every hop.
3. Resolves relative redirects against the current URL.
4. Detects redirect loops and chains beyond the configured limit.
5. Flags final 4xx and 5xx destinations.
6. Flags chains with more than one redirect so they can be shortened.
7. Saves a plain-language diagnosis and a complete machine-readable chain.

The Actor does not require cookies, login credentials, or an external API key. It rejects local and private network destinations and audits only public URLs.

### Redirect loops, dead destinations and long chains

Three failures are flagged explicitly in `issue`. A loop is a chain that returns to a URL it already visited, or that runs past `maxRedirects`. A dead destination is a final response in the 4xx or 5xx range, which is what a visitor sees. A long chain is any URL that needs two or more hops: the first link should point straight at the last one. Set `issuesOnly: true` and only these rows reach the dataset.

### Ready-to-run example

```json
{
  "urls": [
    "http://example.com",
    "https://www.apify.com"
  ],
  "maxRedirects": 10,
  "requestTimeoutSecs": 15,
  "issuesOnly": false
}
````

Every required field has a working default, so the default run completes without configuration. Use `issuesOnly: true` for scheduled checks when you only want actionable failures in the dataset.

### Output example

```json
{
  "inputUrl": "http://example.com",
  "finalUrl": "https://example.com/",
  "finalStatus": 200,
  "redirectCount": 1,
  "hasIssue": false,
  "issue": null,
  "totalDurationMs": 183,
  "chain": [
    {
      "url": "http://example.com/",
      "status": 301,
      "location": "https://example.com/",
      "durationMs": 81
    },
    {
      "url": "https://example.com/",
      "status": 200,
      "location": null,
      "durationMs": 102
    }
  ],
  "checkedAt": "2026-07-20T05:00:00.000Z"
}
```

A run-level `SUMMARY` record reports the number of URLs checked, URLs with issues, and dataset rows returned.

### Data returned for each URL

| Field | What it holds |
|---|---|
| `inputUrl` | The URL submitted |
| `finalUrl` | Where the chain actually ends |
| `finalStatus` | HTTP status of the final response |
| `redirectCount` | Number of hops before the final response |
| `hasIssue` / `issue` | Loop, broken destination, long chain or network failure |
| `totalDurationMs` | Combined request time across the chain |
| `chain[]` | Per hop: url, status, `Location` target, durationMs |

### Reading the diagnosis

A single redirect that reaches a healthy final page is treated as clean. A redirect status without a `Location` header is returned as the final response so the missing destination remains visible. Network failures and timeouts become result rows rather than silently disappearing.

`totalDurationMs` is the combined request time observed during this run. It is useful for comparisons, not a laboratory performance benchmark: geography, server load, and network conditions can change it.

### Limits and responsible use

Runs are capped at 100 input URLs, 20 redirect hops per URL, and 30 seconds per request. The Actor uses ordinary GET requests and cancels response bodies after reading headers. It does not bypass access controls, CAPTCHAs, paywalls, or authentication. Only submit URLs you are authorized to test, and schedule audits at a reasonable frequency.

### Unofficial tool disclaimer

This is an **unofficial, independent tool**. It is not affiliated with or endorsed by any website, browser vendor, search engine, or analytics platform. HTTP behavior can vary by user agent, geography, cookies, and server configuration; confirm critical migration decisions with your own production monitoring.

# Actor input Schema

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

HTTP or HTTPS URLs. Hard maximum: 100 per run.

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

Stop and flag a chain after this many redirect hops.

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

Maximum wait for each redirect hop.

## `issuesOnly` (type: `boolean`):

Omit clean direct destinations and single redirects from the dataset.

## Actor input object example

```json
{
  "urls": [
    "http://example.com",
    "https://www.apify.com"
  ],
  "maxRedirects": 10,
  "requestTimeoutSecs": 15,
  "issuesOnly": false
}
```

# Actor output Schema

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

Structured redirect audit items.

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

Counts of checked URLs and detected issues.

# 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://example.com",
        "https://www.apify.com"
    ],
    "maxRedirects": 10,
    "requestTimeoutSecs": 15,
    "issuesOnly": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("davidbenittah/redirect-chain-auditor").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://example.com",
        "https://www.apify.com",
    ],
    "maxRedirects": 10,
    "requestTimeoutSecs": 15,
    "issuesOnly": False,
}

# Run the Actor and wait for it to finish
run = client.actor("davidbenittah/redirect-chain-auditor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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://example.com",
    "https://www.apify.com"
  ],
  "maxRedirects": 10,
  "requestTimeoutSecs": 15,
  "issuesOnly": false
}' |
apify call davidbenittah/redirect-chain-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=davidbenittah/redirect-chain-auditor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Bulk Redirect Chain Checker & Loop Finder",
        "description": "Trace every hop for up to 100 URLs in one run. This redirect chain checker follows 301, 302, 303, 307 and 308 responses, flags redirect loops, 4xx and 5xx destinations and chains longer than one hop, then returns each full chain with status codes, Location targets and per-hop response times.",
        "version": "1.0",
        "x-build-id": "hISraQwOXjov8n9iY"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/davidbenittah~redirect-chain-auditor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-davidbenittah-redirect-chain-auditor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/davidbenittah~redirect-chain-auditor/runs": {
            "post": {
                "operationId": "runs-sync-davidbenittah-redirect-chain-auditor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/davidbenittah~redirect-chain-auditor/run-sync": {
            "post": {
                "operationId": "run-sync-davidbenittah-redirect-chain-auditor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "urls"
                ],
                "properties": {
                    "urls": {
                        "title": "Public URLs to check",
                        "type": "array",
                        "description": "HTTP or HTTPS URLs. Hard maximum: 100 per run.",
                        "default": [
                            "http://example.com"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxRedirects": {
                        "title": "Maximum redirects per URL",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Stop and flag a chain after this many redirect hops.",
                        "default": 10
                    },
                    "requestTimeoutSecs": {
                        "title": "Timeout per request in seconds",
                        "minimum": 3,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Maximum wait for each redirect hop.",
                        "default": 15
                    },
                    "issuesOnly": {
                        "title": "Return only URLs with issues",
                        "type": "boolean",
                        "description": "Omit clean direct destinations and single redirects from the dataset.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
