Migration Redirect Map Conformance Auditor
Pricing
$1.50 / 1,000 pair checkeds
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
Maintained by CommunityActor 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 (
httpstohttppartway 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}
| Field | Description |
|---|---|
pairs | Old-to-new URL pairs to check. Each item needs oldUrl and expectedNewUrl. Maximum 5,000 pairs per run. |
maxHops | Maximum redirect hops followed per pair when requireSingleHop is false. Default 5; range 1-20. |
requireSingleHop | When 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. |
normalization | Rules 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). |
expectedStatus | The 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. |
concurrency | Pairs checked concurrently. Default 10; maximum 50. |
timeoutSecs | Per-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
GETfallback), 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.
expectedStatusaffects only theEXACTvsMATCH_AFTER_NORMALIZATIONsplit; a pair that lands on the right target is never markedWRONG_TARGETbecause of its status code alone.- Network failures and timeouts are reported as
SERVER_ERRORwith anerrormessage; 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.