{
  "slug": "redirect-checker",
  "url": "https://marketplace.rtila.com/bots/redirect-checker",
  "name": "Redirect Checker",
  "title": "Redirect Checker",
  "tagline": "Check a URL list for redirects: status codes, chains, final destinations and timing in one report.",
  "category": "seo",
  "tags": [
    "seo-audit",
    "redirects",
    "http-status",
    "site-migration",
    "technical-seo"
  ],
  "platforms": [
    "windows",
    "macos",
    "macos_intel",
    "linux"
  ],
  "version": "1.0.0",
  "updatedDate": "2026-09-18",
  "botId": "redirect-checker",
  "price": 0,
  "priceCurrency": "USD",
  "difficulty": "beginner",
  "targetSites": [
    "any URLs you supply and are permitted to test"
  ],
  "updateChannel": "live",
  "requiresInternetAtLaunch": true,
  "artifacts": [
    {
      "os": "windows",
      "sizeBytes": 103674281,
      "sha256": "be2c2caea422661708fcab4608fd90232eca6a9c6aabefe81f0c29113ccc5f79",
      "signed": false,
      "notarized": false,
      "downloadUrl": "https://mp.rtila.net/d/redirect-checker/windows"
    },
    {
      "os": "macos",
      "sizeBytes": 91721872,
      "sha256": "ad2f745b82a49df5fbb6e7147af4022822daee223758b729b37a9ad2541ef7ab",
      "signed": false,
      "notarized": false,
      "downloadUrl": "https://mp.rtila.net/d/redirect-checker/macos"
    },
    {
      "os": "macos_intel",
      "sizeBytes": 104264912,
      "sha256": "c670f0119a303e0abe3a92b5000727920069296a910440271f22a1df53522660",
      "signed": false,
      "notarized": false,
      "downloadUrl": "https://mp.rtila.net/d/redirect-checker/macos_intel"
    },
    {
      "os": "linux",
      "sizeBytes": 128423456,
      "sha256": "8886ba9eaa4907814cb058f863397ad5c9d042a2f4c44543d37ff01763238668",
      "signed": false,
      "notarized": false,
      "downloadUrl": "https://mp.rtila.net/d/redirect-checker/linux"
    }
  ],
  "configEncoding": "plain",
  "configUrl": "https://marketplace.rtila.com/api/bots/redirect-checker/config.json",
  "configDigest": "e1406a349457b08595d37c635806675ee467e834b66b20ad77e627bf740b0a3f",
  "inputSchema": [
    {
      "name": "urls_to_check",
      "kind": "list",
      "required": true,
      "acquisition": "project-settings",
      "default": "https://httpbin.org/redirect/1\nhttps://httpbin.org/redirect/3\nhttps://httpbin.org/status/301\nhttps://httpbin.org/status/302\nhttps://www.google.com\nhttps://this-domain-does-not-exist-9x7q.com",
      "description": "Declared in project settings.",
      "userSupplied": true,
      "authorSpecified": false
    },
    {
      "name": "start_urls",
      "kind": "url",
      "required": true,
      "acquisition": "project-settings",
      "description": "Start URLs the bot navigates to.",
      "userSupplied": true,
      "authorSpecified": false
    }
  ],
  "outputSchema": {
    "datasets": [
      {
        "name": "Redirect_Report",
        "itemCount": 23,
        "itemSelector": "css=html",
        "requiredFields": [
          "Source_URL"
        ],
        "fields": [
          {
            "name": "Source_URL",
            "type": "text",
            "selector": "variable=normalized_url",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Final_URL",
            "type": "text",
            "selector": "variable=last_final_url",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Status_Code",
            "type": "text",
            "selector": "variable=last_http_status",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Status_Text",
            "type": "text",
            "selector": "variable=last_http_status_text",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Redirect_Count",
            "type": "text",
            "selector": "variable=last_redirect_count",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Navigation_OK",
            "type": "text",
            "selector": "variable=last_navigation_ok",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Error",
            "type": "text",
            "selector": "variable=last_navigation_error",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Content_Type",
            "type": "text",
            "selector": "variable=last_content_type",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Server",
            "type": "text",
            "selector": "variable=last_server",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Protocol",
            "type": "text",
            "selector": "variable=last_protocol",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Response_Time_ms",
            "type": "text",
            "selector": "variable=last_response_time_ms",
            "computed": false,
            "transformations": []
          },
          {
            "name": "X_Robots_Tag",
            "type": "text",
            "selector": "variable=last_x_robots_tag",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Cache_Control",
            "type": "text",
            "selector": "variable=last_cache_control",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Chain_Status_Codes",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "if(!Array.isArray(value)||value.length===0)return '';return value.map(function(h){return h.status||'?';}).join(' -> ');",
                  "default_value": ""
                }
              }
            ]
          },
          {
            "name": "Chain_Details",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "if(!Array.isArray(value)||value.length===0)return '';return value.map(function(h,i){return 'Hop '+(i+1)+': '+((h.status)||'?')+' '+(h.location||h.url||'');}).join(' | ');",
                  "default_value": ""
                }
              }
            ]
          },
          {
            "name": "Chain_Visual",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "if(!Array.isArray(value)||value.length===0)return '';var p=[];for(var i=0;i<value.length;i++){var h=value[i];p.push((h.url||'')+' --['+(h.status||'?')+']--> '+(h.location||''));}return p.join('\\n');",
                  "default_value": ""
                }
              }
            ]
          },
          {
            "name": "Has_301",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===301;}));",
                  "default_value": "false"
                }
              }
            ]
          },
          {
            "name": "Has_302",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===302;}));",
                  "default_value": "false"
                }
              }
            ]
          },
          {
            "name": "Has_303",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===303;}));",
                  "default_value": "false"
                }
              }
            ]
          },
          {
            "name": "Has_307",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===307;}));",
                  "default_value": "false"
                }
              }
            ]
          },
          {
            "name": "Has_308",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===308;}));",
                  "default_value": "false"
                }
              }
            ]
          },
          {
            "name": "Redirect_Type",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "var c=Array.isArray(value)?value:[];if(c.length===0)return 'No HTTP Redirect';var s=c.map(function(h){return h.status;});if(s.indexOf(301)!==-1)return '301 Permanent';if(s.indexOf(308)!==-1)return '308 Permanent';if(s.indexOf(302)!==-1)return '302 Temporary';if(s.indexOf(303)!==-1)return '303 See Other';if(s.indexOf(307)!==-1)return '307 Temporary';return 'Redirect ('+s.join(',')+')';",
                  "default_value": "Unknown"
                }
              }
            ]
          },
          {
            "name": "Chain_Length_Verdict",
            "type": "text",
            "selector": "variable=last_redirect_count",
            "computed": false,
            "transformations": [
              {
                "type": "script",
                "parameters": {
                  "code": "var n=Number(value);if(!isFinite(n)||n===0)return 'No Redirect';if(n<=2)return 'OK';if(n<=5)return 'Long Chain';return 'Redirect Loop Risk';",
                  "default_value": "Unknown"
                }
              }
            ]
          }
        ]
      },
      {
        "name": "Errors",
        "itemCount": 3,
        "itemSelector": "css=html",
        "requiredFields": [
          "Source_URL"
        ],
        "fields": [
          {
            "name": "Source_URL",
            "type": "text",
            "selector": "variable=normalized_url",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Status_Code",
            "type": "text",
            "selector": "variable=last_http_status",
            "computed": false,
            "transformations": []
          },
          {
            "name": "Error",
            "type": "text",
            "selector": "variable=last_navigation_error",
            "computed": false,
            "transformations": []
          }
        ]
      },
      {
        "name": "Destination_URLs",
        "itemCount": 1,
        "itemSelector": "css=html",
        "requiredFields": [
          "Destination_URL"
        ],
        "fields": [
          {
            "name": "Destination_URL",
            "type": "text",
            "selector": "variable=last_final_url",
            "computed": false,
            "transformations": []
          }
        ]
      }
    ],
    "fileOutputs": [],
    "destinations": [],
    "exportFormats": [
      "csv",
      "json",
      "xlsx"
    ],
    "datasetAdvisories": []
  },
  "commandsUsed": [
    {
      "name": "for_each",
      "description": "For each command",
      "docsUrl": "https://learn.rtila.com/reference/commands/for_each",
      "count": 1
    }
  ],
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-09-18",
      "botId": "redirect-checker",
      "notes": "Initial release. Per-URL navigation with full redirect-chain capture, three datasets (Redirect_Report, Errors, Destination_URLs), chain formatting and verdict columns via script transformations, resource blocking for speed, and a pre-loaded six-URL self-test list."
    }
  ],
  "faq": [
    {
      "question": "How do I check a list of URLs for redirects in bulk?",
      "answer": "Paste your URLs into the list field, one per line, and start the run. The bot walks the list with up to three parallel workers, navigates each URL, and records the full redirect chain into the Redirect_Report dataset. A six-URL test list is pre-loaded so your very first run doubles as a self-test."
    },
    {
      "question": "What is a redirect chain and why does its length matter?",
      "answer": "A chain is the sequence of hops between the URL you submit and the URL the browser finally lands on. Each hop costs latency and can leak ranking signals if intermediate URLs are temporary. The Chain_Status_Codes, Chain_Details and Chain_Visual columns show every hop, and Chain_Length_Verdict grades it: OK at two hops or fewer, Long Chain up to five, Redirect Loop Risk beyond that."
    },
    {
      "question": "How do I find 302 redirects that should be 301?",
      "answer": "Filter the Redirect_Report output on the Has_302 column or on Redirect_Type showing 302 Temporary. A permanent move served as a temporary redirect tells crawlers the old URL may return, which is the most common migration mistake this bot surfaces."
    },
    {
      "question": "What is the difference between 301 302 303 307 and 308 status codes?",
      "answer": "301 is a permanent move that may rewrite the request method; 308 is permanent but preserves the method; 302 is temporary and may rewrite the method; 307 is temporary and preserves the method; 303 tells the client to fetch another resource with a GET. For SEO auditing the practical split is permanent (301, 308) versus temporary (302, 307), and the Redirect_Type column classifies each URL accordingly."
    },
    {
      "question": "How do I audit redirects after a website migration?",
      "answer": "Export your old URL list from the previous CMS, sitemap or server logs, paste it into the checker, and run it against the live site. Then review three things: URLs whose Final_URL is not the intended new page, rows where Redirect_Type says temporary, and rows where Chain_Length_Verdict flags Long Chain or Redirect Loop Risk. Re-run the same list weekly to catch regressions."
    },
    {
      "question": "Why does the checker block images scripts and stylesheets?",
      "answer": "The bot only needs the navigation itself, not the rendered page. Blocking images, media, fonts, styles, scripts and background requests makes each check dramatically faster and lighter on bandwidth. The trade-off is documented in the limits section: a redirect that only fires from client-side script will not be observed."
    },
    {
      "question": "Can it detect redirect loops?",
      "answer": "Yes, indirectly and honestly. A browser gives up on a loop and the navigation fails, so the URL lands in the Errors dataset with Navigation_OK false and the engine error text. Chains that are merely very long are graded Redirect Loop Risk by the Chain_Length_Verdict column before they become hard failures."
    },
    {
      "question": "What do I do with a URL that returns no redirect?",
      "answer": "Nothing is wrong - Redirect_Type reads No HTTP Redirect and Chain_Length_Verdict reads No Redirect, with Status_Code showing the direct response, usually 200. In a migration audit these rows deserve attention: an old URL still serving content directly instead of forwarding is a duplicate-content risk."
    },
    {
      "question": "How many URLs can one run check?",
      "answer": "There is no built-in cap; the list length governs the run. Three workers process URLs in parallel, so a few hundred typical URLs finish in minutes. Very large lists mainly need patience and proportionate request rates against the target server."
    },
    {
      "question": "Does the bot follow redirects all the way to the final destination?",
      "answer": "Yes. Navigation behaves exactly like a real browser session: the engine follows every hop, then records the final URL, the final status, the response headers of the last hop, and the full chain of intermediate statuses and locations."
    },
    {
      "question": "Can I check redirects without a paid SEO tool?",
      "answer": "That is the point of this bot. It is a free desktop launcher, your URL list never leaves your machine except as requests to the URLs themselves, and the report exports to CSV, JSON or XLSX for review in any spreadsheet."
    },
    {
      "question": "Does the bot need an internet connection to run?",
      "answer": "Yes on first run: the launcher fetches its configuration by id from the backend at launch, so an internet connection is required at least the first time it starts."
    },
    {
      "question": "Can I rename the downloaded file?",
      "answer": "No. The downloaded file must keep its exact name - the filename carries the per-bot configuration id, and renaming it breaks the configuration fetch at launch."
    }
  ],
  "remote": {
    "visibility": "public",
    "activation": {
      "mode": "always-on"
    }
  },
  "project": {
    "name": "Redirect Checker",
    "settings": {
      "urls": [
        "about:blank"
      ],
      "headless": false,
      "max_concurrent_workers": 3,
      "humanoidEnabled": false,
      "proxyEnabled": false,
      "captchaEnabled": false,
      "matchTimezoneAndLocale": false,
      "block_resources": false,
      "get_urls_from_sitemap": false,
      "respect_robots_txt": false,
      "skip_initial_navigation": true,
      "variables": [
        {
          "name": "urls_to_check",
          "value": "https://httpbin.org/redirect/1\nhttps://httpbin.org/redirect/3\nhttps://httpbin.org/status/301\nhttps://httpbin.org/status/302\nhttps://www.google.com\nhttps://this-domain-does-not-exist-9x7q.com",
          "required": true,
          "is_list": true
        }
      ]
    },
    "datasets": {
      "Redirect_Report": {
        "item_selector": "css=html",
        "properties": [
          {
            "name": "Source_URL",
            "type": "text",
            "selector": "variable=normalized_url"
          },
          {
            "name": "Final_URL",
            "type": "text",
            "selector": "variable=last_final_url"
          },
          {
            "name": "Status_Code",
            "type": "text",
            "selector": "variable=last_http_status"
          },
          {
            "name": "Status_Text",
            "type": "text",
            "selector": "variable=last_http_status_text"
          },
          {
            "name": "Redirect_Count",
            "type": "text",
            "selector": "variable=last_redirect_count"
          },
          {
            "name": "Navigation_OK",
            "type": "text",
            "selector": "variable=last_navigation_ok"
          },
          {
            "name": "Error",
            "type": "text",
            "selector": "variable=last_navigation_error"
          },
          {
            "name": "Content_Type",
            "type": "text",
            "selector": "variable=last_content_type"
          },
          {
            "name": "Server",
            "type": "text",
            "selector": "variable=last_server"
          },
          {
            "name": "Protocol",
            "type": "text",
            "selector": "variable=last_protocol"
          },
          {
            "name": "Response_Time_ms",
            "type": "text",
            "selector": "variable=last_response_time_ms"
          },
          {
            "name": "X_Robots_Tag",
            "type": "text",
            "selector": "variable=last_x_robots_tag"
          },
          {
            "name": "Cache_Control",
            "type": "text",
            "selector": "variable=last_cache_control"
          },
          {
            "name": "Chain_Status_Codes",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "if(!Array.isArray(value)||value.length===0)return '';return value.map(function(h){return h.status||'?';}).join(' -> ');",
                "default_value": ""
              }
            ]
          },
          {
            "name": "Chain_Details",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "if(!Array.isArray(value)||value.length===0)return '';return value.map(function(h,i){return 'Hop '+(i+1)+': '+((h.status)||'?')+' '+(h.location||h.url||'');}).join(' | ');",
                "default_value": ""
              }
            ]
          },
          {
            "name": "Chain_Visual",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "if(!Array.isArray(value)||value.length===0)return '';var p=[];for(var i=0;i<value.length;i++){var h=value[i];p.push((h.url||'')+' --['+(h.status||'?')+']--> '+(h.location||''));}return p.join('\\n');",
                "default_value": ""
              }
            ]
          },
          {
            "name": "Has_301",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===301;}));",
                "default_value": "false"
              }
            ]
          },
          {
            "name": "Has_302",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===302;}));",
                "default_value": "false"
              }
            ]
          },
          {
            "name": "Has_303",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===303;}));",
                "default_value": "false"
              }
            ]
          },
          {
            "name": "Has_307",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===307;}));",
                "default_value": "false"
              }
            ]
          },
          {
            "name": "Has_308",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "return String(Array.isArray(value)&&value.some(function(h){return h.status===308;}));",
                "default_value": "false"
              }
            ]
          },
          {
            "name": "Redirect_Type",
            "type": "text",
            "selector": "variable=last_redirect_chain",
            "transformations": [
              {
                "type": "script",
                "code": "var c=Array.isArray(value)?value:[];if(c.length===0)return 'No HTTP Redirect';var s=c.map(function(h){return h.status;});if(s.indexOf(301)!==-1)return '301 Permanent';if(s.indexOf(308)!==-1)return '308 Permanent';if(s.indexOf(302)!==-1)return '302 Temporary';if(s.indexOf(303)!==-1)return '303 See Other';if(s.indexOf(307)!==-1)return '307 Temporary';return 'Redirect ('+s.join(',')+')';",
                "default_value": "Unknown"
              }
            ]
          },
          {
            "name": "Chain_Length_Verdict",
            "type": "text",
            "selector": "variable=last_redirect_count",
            "transformations": [
              {
                "type": "script",
                "code": "var n=Number(value);if(!isFinite(n)||n===0)return 'No Redirect';if(n<=2)return 'OK';if(n<=5)return 'Long Chain';return 'Redirect Loop Risk';",
                "default_value": "Unknown"
              }
            ]
          }
        ],
        "required_fields": [
          "Source_URL"
        ]
      },
      "Errors": {
        "item_selector": "css=html",
        "properties": [
          {
            "name": "Source_URL",
            "type": "text",
            "selector": "variable=normalized_url"
          },
          {
            "name": "Status_Code",
            "type": "text",
            "selector": "variable=last_http_status"
          },
          {
            "name": "Error",
            "type": "text",
            "selector": "variable=last_navigation_error"
          }
        ],
        "required_fields": [
          "Source_URL"
        ]
      },
      "Destination_URLs": {
        "item_selector": "css=html",
        "properties": [
          {
            "name": "Destination_URL",
            "type": "text",
            "selector": "variable=last_final_url"
          }
        ],
        "required_fields": [
          "Destination_URL"
        ]
      }
    },
    "commands": [
      {
        "command": "for_each",
        "params": {
          "source_type": "variable",
          "variable": "urls_to_check",
          "as": "target_url",
          "do": [
            {
              "command": "try_catch",
              "params": {
                "try": [
                  {
                    "command": "goto",
                    "params": {
                      "url": "${target_url}"
                    }
                  }
                ],
                "catch": [
                  {
                    "command": "comment",
                    "params": {
                      "text": "Navigation failed: ${last_error}"
                    }
                  }
                ]
              }
            },
            {
              "command": "extract_data",
              "params": {
                "dataset": "Redirect_Report"
              }
            },
            {
              "command": "extract_data",
              "params": {
                "dataset": "Errors",
                "filter_condition": "item.Navigation_OK === false || item.Status_Code === null || item.Status_Code === ''"
              }
            },
            {
              "command": "extract_data",
              "params": {
                "dataset": "Destination_URLs",
                "filter_condition": "item.Destination_URL && item.Destination_URL !== ''"
              }
            }
          ]
        }
      }
    ],
    "authors": []
  }
}