A 301 redirect says a page has moved for good; a 302 says the move is temporary and the old address will be back. Search engines act on that difference: after a 301 they index the new address in place of the old one, after a 302 they usually keep the old one. Use a 301 (or a 308) for anything permanent, such as a renamed page, a new domain or the switch to HTTPS, and a 302 (or a 307) only when the original address really will return. Keep every redirect to a single hop, and check it with a tool that shows each step.
The redirect status codes
A redirect is a response in the 3xx range with a Location header that names the new address. Five codes matter in practice:
| Code | Meaning | Keeps the method | Use it for |
|---|---|---|---|
| 301 Moved Permanently | Moved for good | Not guaranteed: browsers turn a POST into a GET | Renamed pages, new domains, HTTP to HTTPS |
| 302 Found | Temporarily elsewhere | Not guaranteed: browsers turn a POST into a GET | Short-term moves, sending visitors to a login page |
| 303 See Other | Get the result from another address | No, always a GET | After a form is submitted, so a reload doesn’t send it twice |
| 307 Temporary Redirect | Temporarily elsewhere | Yes, method and body | Temporary moves of API endpoints and forms |
| 308 Permanent Redirect | Moved for good | Yes, method and body | Permanent moves of API endpoints and forms |
For ordinary pages, which browsers fetch with GET, 301 and 308 behave the same, and so do 302 and 307. The difference shows up when a client sends a POST: after a 301 or 302 most clients repeat it as a GET without the body, while 307 and 308 make them send the same request again. That is why APIs that move an endpoint should use 308 or 307. The full list of codes is in the HTTP status code reference.
What redirects do to SEO
Google’s documentation on redirects treats 301 and 308 as permanent and 302, 303 and 307 as temporary. A permanent redirect is a strong signal that the target should be shown in search results instead of the old address. A temporary redirect is a weak one, so the old address usually stays indexed.
That gives three common mistakes:
- A 302 for a permanent move. Many frameworks and plugins redirect with 302 by default. After a site move, check that the redirects really answer 301 or 308.
- Redirecting everything to the homepage. When an old page has no counterpart, Google may treat a redirect to the homepage as a soft 404. Send each old page to its closest match, or let it answer 404 or 410.
- Old links pointing at redirects. A redirect is a safety net, not a destination. Update internal links, canonical tags and the sitemap to the final address, so neither visitors nor crawlers pay for the extra hop.
Server-side redirects are the clearest signal. Meta refresh tags and JavaScript redirects work for visitors, but search engines only see them after loading the page, and other clients may not see them at all.
Which one to use
- A page was renamed or merged into another: 301.
- The site moved to a new domain, or to HTTPS, or between www and the bare domain: 301 from every old variant straight to the final address.
- A page is temporarily somewhere else, for a campaign or while it is rebuilt: 302.
- A visitor must log in first: 302 to the login page, then back.
- A form was submitted: 303 to the result page.
- An API endpoint moved: 308 if for good, 307 if for now, so clients keep their method and body.
- The site is down for maintenance: no redirect. Answer 503 Service Unavailable on the original address, so search engines come back later instead of indexing a maintenance page.
Browsers remember permanent redirects
Browsers cache 301 and 308 responses, often for a long time, and follow them without asking the server again. A wrong permanent redirect therefore keeps sending returning visitors to the wrong place even after you fix the server. When you set up a new rule, test it as a 302 first, and switch it to a 301 once it is right. If a bad 301 has already gone out, a Cache-Control: no-store header on future redirects helps new visitors, but the copies browsers already hold expire on their own schedule.
Redirect chains and loops
A chain is a redirect to an address that redirects again: http://example.com to https://example.com to https://www.example.com to https://www.example.com/en/. Every hop is another round trip before the page starts loading, and Google follows at most 10 hops. Chains grow over years of site moves, each one adding its rule on top of the last. Fix them by sending every old variant directly to the final address in one hop.
A loop is a chain that never ends: two rules send visitors back and forth until the browser gives up with “too many redirects”. The usual causes:
- HTTP and HTTPS. A CDN talks to your server over HTTP, while the server redirects every HTTP request to HTTPS. Behind Cloudflare, this is the Flexible SSL setting; Full (strict) fixes it.
- www and the bare domain. The web server adds www and the application removes it, or the other way around. In WordPress, check that the WordPress Address and Site Address agree with the server’s rule.
- Trailing slashes and language rules. One rule adds a slash or a language prefix, another removes it.
How to check a redirect
From a terminal, curl shows every hop with its status code and Location header:
curl -sIL http://example.com/old-page | grep -iE "^(HTTP|location)"
HTTP/1.1 301 Moved Permanently
Location: https://example.com/old-page
HTTP/2 301
location: https://example.com/new-page
HTTP/2 200
Two hops: the second rule should have been the first. In a browser, open the developer tools, tick Preserve log on the Network tab and load the old address; each redirect is its own row. Remember that the browser may answer a 301 from its cache, so a private window gives a cleaner picture.
Or use our free redirect checker: enter a URL to see each hop with its status code, where the chain ends, and whether it loops, runs long or uses a temporary redirect where you probably meant a permanent one. It follows up to 5 hops, checked live from Stockholm.
Setting up a 301
Most hosts and CDNs have a redirect setting in their dashboard. In server configuration:
# nginx: one page
location = /old-page { return 301 /new-page; }
# nginx: a whole domain, keeping the path
server {
server_name old-example.com www.old-example.com;
return 301 https://example.com$request_uri;
}
# Apache (.htaccess): one page
Redirect 301 /old-page /new-page
Afterwards, check the old address, its HTTP and www variants, and an address with a query string, and make sure each one reaches the final page in one hop.
Monitoring redirects with Uptimecheck
An HTTP(S) monitor in Uptimecheck uptime monitoring follows up to 10 redirects by default and judges the page at the end, which counts as up when it answers with a status from 200 to 399. A loop, or a chain longer than that, is reported as down with “Too many redirects”, and the incident says when the chain bounces between HTTP and HTTPS or between www and the bare domain. Checks run as often as every minute from Stockholm, Sweden, and a second check confirms a failure before you are alerted.
To watch the redirect itself, for example after a domain move, turn off Follow redirects so the monitor judges the redirect’s own status code, set Expected status codes to 301, and add a header check that Location equals the new address. If someone later changes the redirect to a 302 or points it somewhere else, you hear about it. See how to add your first monitor and the guide to HTTP status codes in monitoring.
Know when a move breaks. Try Uptimecheck free for 14 days, no credit card required.