# Site Migration Redirect Map Validator & Audit (`burly_bat/site-migration-redirect-map-qa`) Actor

Validate old-to-new URL migration maps in bulk before or after launch. Find broken 301/308 redirects, wrong final destinations, redirect chains, canonical mismatches, noindex pages, loops, and HTTPS downgrades. Export PASS/WARN/FAIL results to JSON, CSV, Excel, Markdown, and HTML.

- **URL**: https://apify.com/burly\_bat/site-migration-redirect-map-qa.md
- **Developed by:** [Burly Bat](https://apify.com/burly_bat) (community)
- **Categories:** SEO tools, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 validated migration mappings

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 web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Site Migration Redirect Map Validator & Audit

Validate an entire **old URL → expected new URL** migration map before or after launch.
This Actor follows every redirect manually, checks the actual final destination and turns
raw HTTP behavior into a deployment gate your SEO, engineering and QA teams can act on.

### Why use this instead of a generic status checker?

A status checker tells you that an old URL eventually returned `200`. It does not tell you
whether it reached the **correct page from your migration spreadsheet**. This Actor treats
the mapping as a contract and validates both sides.

For each pair it checks:

- direct permanent `301` or `308` from the old URL;
- temporary redirects (`302`, `303`, `307`);
- every redirect hop, loops, missing `Location` and excessive chains;
- actual final URL versus the expected mapped target;
- final `2xx` status and HTTPS downgrade;
- self-referencing canonical from HTML or the HTTP `Link` header;
- `noindex` from meta robots, Googlebot meta and `X-Robots-Tag`;
- many old URLs mapped to the same destination;
- deterministic `PASS`, `WARN` or `FAIL`, issue codes and repair guidance.

Outputs include a dataset (JSON/CSV/Excel), JSON summary, Markdown summary and a
self-contained HTML report with a batch-level `deploymentGate`.

### Quick start

Paste two columns copied from Excel or Google Sheets:

```text
sourceUrl,expectedTargetUrl,rowId
https://old.example.com/pricing,https://new.example.com/pricing,pricing
https://old.example.com/docs,https://new.example.com/help,docs
```

You can also call the Actor with structured JSON:

```json
{
  "mappings": [
    {
      "sourceUrl": "https://old.example.com/pricing",
      "expectedTargetUrl": "https://new.example.com/pricing",
      "rowId": "pricing"
    }
  ],
  "ignoreTrailingSlash": true,
  "ignoreQueryString": false,
  "checkCanonical": true,
  "checkIndexability": true
}
```

### Result fields

Each dataset row contains:

- `sourceUrl`, `expectedTargetUrl`, `finalUrl`, optional `rowId`;
- `sourceStatusCode`, `finalStatusCode`, `redirectCount`, `redirectChain`;
- `isDirectPermanentRedirect`, `hasTemporaryRedirect`, `matchesExpectedTarget`;
- `canonicalUrl`, `canonicalMatchesTarget`, `robotsDirectives`, `isNoindex`;
- `resolved`, `confidence`, `verdict`, `issueCodes`, `issues`;
- response time and audit timestamp.

Common issue codes: `SOURCE_NOT_REDIRECT`, `TEMPORARY_REDIRECT`, `REDIRECT_CHAIN`,
`WRONG_DESTINATION`, `TARGET_NOT_OK`, `HTTPS_DOWNGRADE`, `MISSING_CANONICAL`,
`CANONICAL_MISMATCH`, `TARGET_NOINDEX`, `MANY_TO_ONE_TARGET`, `REDIRECT_LOOP`.

### How verdicts work

- **PASS** — direct permanent redirect, expected destination, healthy target and no
  enabled canonical/indexability defect.
- **WARN** — deploy may be possible, but the audit found quality risks such as a redirect
  chain, missing canonical or intentional many-to-one consolidation.
- **FAIL** — wrong destination, temporary/no redirect, broken/noindex target, canonical
  mismatch, loop, HTTPS downgrade or an unresolved network/safety failure.

`deploymentGate` is `FAIL` when any mapping fails. JavaScript-only redirects or tags are
not rendered; a non-HTML/blocked target is marked low-confidence and should be checked in
a browser.

### Security and responsible use

- Audit only public URLs you own or are authorized to test.
- The Actor blocks localhost, private/link-local/reserved IP ranges, cloud metadata hosts,
  URL credentials and non-standard ports. Every redirect hop is checked again.
- Responses are capped, requests time out and concurrency is bounded.
- No personal data, login credentials, proxy or external API is required.
- This is technical QA, not a guarantee of rankings or legal/SEO advice.

### Pricing

Pay per event: **$0.005 per source URL that returns a resolved final HTTP response**
(that is $5.00 per 1,000 checked mappings), plus a near-zero `$0.00005` Actor start event.

- A mapping is charged whenever the source URL resolves to a final HTTP response, no matter
  whether its verdict is `PASS`, `WARN` or `FAIL` — a detected 404 or a wrong target is a
  result you are paying for.
- Invalid expected targets, blocked URLs, DNS failures and connection failures are **never
  charged**, even though they are still delivered to the dataset.
- Platform usage is covered by the Actor creator, so the event price is what you pay.
- Set `maxTotalChargeUsd` on the run to cap your spend. The Actor trims the input before doing
  any work, so your limit is never exceeded and `skippedByChargeLimit` reports what was left out.

### Recommended workflow

1. Export the final migration map from your spreadsheet.
2. Run this Actor on staging or immediately after redirect deployment.
3. Fix every `FAIL`, review `WARN`, then rerun until `deploymentGate` is `PASS`.
4. Export CSV/Excel for the implementation team and archive the HTML report.
5. Schedule a short follow-up audit after launch if redirect rules may change.

### Sources

- [Google: Site moves with URL changes](https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes)
- [Google: Redirects and Search](https://developers.google.com/search/docs/crawling-indexing/301-redirects)
- [Google: Canonical URLs](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls)
- [Google: Robots meta and X-Robots-Tag](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag)
- [HTTP Semantics — RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html)

### Support boundaries

This Actor deliberately uses deterministic HTTP and server-rendered HTML. It does not log
in, bypass bot protection, render JavaScript or crawl a website automatically. Those limits
keep audits reproducible, inexpensive and low-maintenance.

# Actor input Schema

## `mappingText` (type: `string`):

One sourceUrl and expectedTargetUrl pair per line. A header row is optional. Paste directly from Excel or Google Sheets.

## `mappings` (type: `array`):

Alternative structured input. Each item needs sourceUrl and expectedTargetUrl; rowId is optional.

## `maxMappings` (type: `integer`):

Safety cap applied after combining text and JSON inputs.

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

Stop and fail a mapping when its redirect chain exceeds this limit.

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

Maximum time to wait for each redirect hop or final response.

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

Keep this conservative when auditing one host to avoid overloading it.

## `ignoreTrailingSlash` (type: `boolean`):

Treat /page and /page/ as the same expected destination.

## `ignoreQueryString` (type: `boolean`):

Off by default because losing parameters can be a migration defect.

## `checkCanonical` (type: `boolean`):

Validate rel=canonical in server-rendered HTML and the HTTP Link header.

## `checkIndexability` (type: `boolean`):

Fail a mapping when the final HTML or response headers contain noindex.

## Actor input object example

```json
{
  "mappingText": "sourceUrl,expectedTargetUrl,rowId\nhttps://httpbingo.org/redirect-to?url=https%3A%2F%2Fhttpbingo.org%2Fhtml&status_code=301,https://httpbingo.org/html,demo-1",
  "maxMappings": 1000,
  "maxRedirects": 10,
  "timeoutSecs": 20,
  "maxConcurrency": 8,
  "ignoreTrailingSlash": true,
  "ignoreQueryString": false,
  "checkCanonical": true,
  "checkIndexability": true
}
```

# Actor output Schema

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

One PASS/WARN/FAIL record per source-to-target mapping.

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

Counts, deployment gate and issue frequencies.

## `htmlReport` (type: `string`):

Self-contained, safely escaped report for browser review.

## `markdownSummary` (type: `string`):

Portable audit summary for tickets, docs or pull requests.

# 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 = {
    "mappingText": `sourceUrl,expectedTargetUrl,rowId
https://httpbingo.org/redirect-to?url=https%3A%2F%2Fhttpbingo.org%2Fhtml&status_code=301,https://httpbingo.org/html,demo-1`
};

// Run the Actor and wait for it to finish
const run = await client.actor("burly_bat/site-migration-redirect-map-qa").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 = { "mappingText": """sourceUrl,expectedTargetUrl,rowId
https://httpbingo.org/redirect-to?url=https%3A%2F%2Fhttpbingo.org%2Fhtml&status_code=301,https://httpbingo.org/html,demo-1""" }

# Run the Actor and wait for it to finish
run = client.actor("burly_bat/site-migration-redirect-map-qa").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 '{
  "mappingText": "sourceUrl,expectedTargetUrl,rowId\\nhttps://httpbingo.org/redirect-to?url=https%3A%2F%2Fhttpbingo.org%2Fhtml&status_code=301,https://httpbingo.org/html,demo-1"
}' |
apify call burly_bat/site-migration-redirect-map-qa --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=burly_bat/site-migration-redirect-map-qa",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/QLndZmbZxzPO0CMGd/builds/qCCnfb2WX0H9tObMd/openapi.json
