Migration Redirect Map Conformance Auditor avatar

Migration Redirect Map Conformance Auditor

Pricing

$1.50 / 1,000 pair checkeds

Go to Apify Store
Migration Redirect Map Conformance Auditor

Migration Redirect Map Conformance Auditor

Check a domain-migration redirect map: for each old-to-new URL pair, follow the live redirect chain and verify it lands on the expected target, within bounded hops.

Pricing

$1.50 / 1,000 pair checkeds

Rating

0.0

(0)

Developer

kingii98

kingii98

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Categories

Share

Check a domain-migration redirect map. Give the Actor a list of old-URL to expected-new-URL pairs. For each pair, the Actor follows the live redirect chain from the old URL and checks if it lands on the expected target. It reports a verdict for each pair and a launch gate that is true only when every pair passes.

This Actor is for the sign-off step before or after a cutover: confirm the redirect map does what it claims, with no browser and no login.

What it checks

  • The live redirect chain from each oldUrl, up to a bounded number of hops
  • If the chain lands on expectedNewUrl, exactly or after normalization
  • The HTTP status code of the first hop, against expectedStatus
  • Chains that are too long, that loop, that dead-end on a 404, or that hit a server error
  • Protocol downgrades (https to http partway through the chain)
  • Cross-host hops (a redirect that changes host)
  • Response time for each pair, in milliseconds

Each hop is checked with HEAD first. If the origin rejects HEAD (status 405 or 501), the Actor retries that hop with a bounded GET and reads only enough of the body to confirm the status and headers.

Input

{
"pairs": [
{
"oldUrl": "https://old.example.com/blog/post-1",
"expectedNewUrl": "https://new.example.com/blog/post-1"
}
],
"maxHops": 5,
"requireSingleHop": true,
"normalization": {
"ignoreTrailingSlash": true,
"ignoreCase": false,
"ignoreQueryParams": ["utm_source"]
},
"expectedStatus": 301,
"concurrency": 10,
"timeoutSecs": 20
}
FieldDescription
pairsOld-to-new URL pairs to check. Each item needs oldUrl and expectedNewUrl. Maximum 5,000 pairs per run.
maxHopsMaximum redirect hops followed per pair when requireSingleHop is false. Default 5; range 1-20.
requireSingleHopWhen true (default), a pair must land on its target in exactly one redirect hop; any extra hop reports CHAIN_TOO_LONG. When false, maxHops applies instead.
normalizationRules used only to decide a MATCH_AFTER_NORMALIZATION verdict: ignoreTrailingSlash (boolean), ignoreCase (boolean), ignoreQueryParams (list of query-parameter names to ignore when comparing the final URL to expectedNewUrl).
expectedStatusThe HTTP status the first hop must return for a pair to qualify as EXACT. Default 301. A pair that reaches the right target with a different status is MATCH_AFTER_NORMALIZATION, not EXACT.
concurrencyPairs checked concurrently. Default 10; maximum 50.
timeoutSecsPer-request timeout applied to each hop. Default 20 seconds; range 2-60.

Invalid input (empty or oversized pairs, entries missing oldUrl or expectedNewUrl, non-HTTP(S) URLs, URLs with credentials) fails fast with a clear validation error before any network work.

Output

Every run writes one summary record and one pair-result record per pair to the default dataset.

Summary:

{
"recordType": "summary",
"checkedAt": "2026-08-31T09:15:00+00:00",
"pairsRequested": 2,
"pairsChecked": 2,
"verdictCounts": {
"EXACT": 1,
"MATCH_AFTER_NORMALIZATION": 0,
"WRONG_TARGET": 0,
"CHAIN_TOO_LONG": 0,
"LOOP": 0,
"DEAD_END_404": 1,
"SERVER_ERROR": 0
},
"launchGate": false,
"truncatedByChargeBudget": false
}

Pair result:

{
"recordType": "pair-result",
"oldUrl": "https://old.example.com/blog/post-1",
"expectedNewUrl": "https://new.example.com/blog/post-1",
"finalUrl": "https://new.example.com/blog/post-1",
"hopCount": 1,
"hops": [
{"url": "https://old.example.com/blog/post-1", "status": 301, "location": "https://new.example.com/blog/post-1"},
{"url": "https://new.example.com/blog/post-1", "status": 200, "location": null}
],
"verdict": "EXACT",
"statusOfFirstHop": 301,
"protocolDowngradeFlag": false,
"crossHostFlag": true,
"responseTimeMs": 184,
"error": null,
"checkedAt": "2026-08-31T09:15:00+00:00"
}

Verdicts: EXACT (right target, right status, within the hop limit), MATCH_AFTER_NORMALIZATION (right target, but only after applying the normalization rules, or with a first-hop status other than expectedStatus), WRONG_TARGET, CHAIN_TOO_LONG, LOOP, DEAD_END_404, SERVER_ERROR.

launchGate is true only when every pair in the run is EXACT or MATCH_AFTER_NORMALIZATION, and pairsChecked equals pairsRequested. If the run's maximum total charge stops the Actor from auditing every submitted pair, truncatedByChargeBudget is true, pairsChecked is lower than pairsRequested, and launchGate is false even if every audited pair passed. This stops a partial audit from reporting a false pass. Use launchGate as a single pass/fail signal before or after a cutover.

Pricing

The Actor uses Apify pay-per-event pricing with the pair-checked charge event. When monetization is enabled, users are charged $0.0015 per URL pair checked. One pair-checked event corresponds to one pairs entry audited, including every hop the Actor follows for that pair.

Apify platform usage (compute units and other resources consumed by the run) may still be shown to users according to their plan and Apify's pricing rules, as described in the Actor's listing.

The Actor respects the run's maximum total charge: it computes the chargeable pair prefix from the Actor charging budget before any network work, audits only that prefix, and stops before pair checks if no pair can be charged.

Final pricing is configured in the Apify Store listing and may change subject to Apify's pricing-change notice rules.

Security and privacy

  • Only public HTTP(S) targets are accepted; no login flow is supported.
  • URL credentials, localhost, and non-public, loopback, link-local, multicast, unspecified, or reserved addresses are rejected.
  • Every hop target is resolved and validated as a public address before it is followed; a redirect to a private address fails that pair with an error instead of being fetched.
  • Pair count, hop count, concurrency, response bytes (for the GET fallback), and timeouts are all capped before or during network work.
  • The Actor does not use a browser, proxy, LLM, external database, or third-party analytics service.
  • Each run is stateless; results live only in the run's default dataset, subject to the retention and access settings of the Apify account running the Actor.

Do not place secrets, private URLs, or personal data in any input field.

Limitations

  • The Actor checks status codes and redirect targets; it does not render or compare page content.
  • expectedStatus affects only the EXACT vs MATCH_AFTER_NORMALIZATION split; a pair that lands on the right target is never marked WRONG_TARGET because of its status code alone.
  • Network failures and timeouts are reported as SERVER_ERROR with an error message; they are not automatically retried.
  • The Actor does not send notifications itself. Use Apify schedules, webhooks, or an automation platform for the day 1 / day 7 / day 30 / day 90 re-check schedule.

Support

For reproducible issues, open an issue from the Actor page and include the Apify run ID, sanitized input, expected result, and affected public URL. Do not include API tokens or private data.

This Actor audits redirect-map conformance; it does not provide legal, security-audit, or uptime guarantees.