Crawl Rate - Migrations
A Rough Guide to HTTP Redirect Codes: 301, 302, 303, 307 & 308
TL;DR:
HTTP redirects send users and search engines from one URL to another, but different 3xx status codes communicate different things. For most SEO work, a 301 is the standard choice for a permanent URL change, while 302 is temporary. 307 and 308 preserve the original request method, while 303 is mainly used when a subsequent request should use GET. This guide explains when to use each redirect, how to implement common 301s, and how to find redirect chains, loops and other problems.
Why understanding redirect codes matters
If you’ve ever moved a website, changed its URL structure or removed a page, you’ll probably have had to deal with redirects.
As a website migration consultant, they’re something I work with regularly. A badly planned redirect can send users to the wrong page, create redirect chains or loops, and leave search engines trying to work out what happened to the original URL.
But not every redirect means the same thing.
301 and 308 are permanent redirects. 302 and 307 are temporary redirects. 303 has a different job again, particularly when dealing with POST requests.
For most SEO work you’ll spend far more time dealing with 301s than anything else, but understanding the differences becomes important when you’re auditing a website, planning a migration or trying to work out why a particular redirect is behaving unexpectedly.
This is my rough guide to the main HTTP redirect codes, when I’d use each one, how they affect SEO, how to implement common redirects and how to find the problems they can create.
What are HTTP redirect codes?
HTTP redirect codes are 3xx HTTP status codes returned by a server when the requested resource is available somewhere else or the client needs to take another action.
In a typical redirect, someone requests:
and the server responds with a redirect status and a new location:
301 Moved PermanentlyLocation: https://example.com/new-page/
The browser or crawler can then request the new URL.
The important part is that different 3xx status codes communicate different things. Some redirects are permanent, some are temporary, and some determine whether the original HTTP request method should be preserved.
For SEO, the distinction between temporary and permanent redirects is particularly important because it helps search engines understand whether the original URL has moved for good or is expected to return.
What are the different HTTP 3xx redirect codes?
| Code | Meaning | Permanent? | Preserves request method? | Typical use |
|---|---|---|---|---|
| 300 | Multiple Choices | No | N/A | Multiple possible responses |
| 301 | Moved Permanently | Yes | Not guaranteed for non-GET | Permanent URL changes |
| 302 | Found | No | Not guaranteed for non-GET | Temporary URL changes |
| 303 | See Other | No | No – subsequent request is GET | Redirect after POST/PUT |
| 307 | Temporary Redirect | No | Yes | Temporary redirect where method must be preserved |
| 308 | Permanent Redirect | Yes | Yes | Permanent redirect where method must be preserved |
Is there a 310 redirect?
310 isn’t a standard HTTP redirect status code.
Standard HTTP redirect responses sit within the 300–399 range, but that doesn’t mean every number in that range has a defined redirect status.
If you’re seeing a 310 response somewhere, it’s likely to be application-specific or non-standard rather than a normal HTTP redirect code.
301 redirects
What is a 301 redirect?
A 301 Moved Permanently response tells browsers and search engines that a URL has permanently moved to a new location.
For example:
https://example.com/old-page/ → https://example.com/new-page/
For SEO, this is the redirect I use most often. If I’m changing a URL, consolidating pages or carrying out a website migration, a 301 tells Google that the old URL has been permanently replaced by the destination URL.
Google recommends using server-side permanent redirects such as 301 or 308 when URLs have permanently moved.
When should you use a 301 redirect?
I’d use a 301 when the URL change is intended to be permanent.
Typical examples include:
- Migrating a website to a new domain
- Changing the URL structure of a website
- Consolidating several pages into one
- Renaming or changing the URL of a page
- Redirecting HTTP URLs to HTTPS
- Standardising
wwwand non-wwwversions of a website
The destination should be the most relevant replacement for the old URL. I wouldn’t automatically redirect every deleted URL to the homepage simply to avoid returning a 404.
That’s particularly important during a website migration, where I want each important old URL mapped directly to its closest equivalent on the new site.
Do 301 redirects pass SEO value?
Yes. A properly implemented 301 allows Google to treat the destination as the permanent replacement for the original URL.
I wouldn’t think of this as a fixed percentage of “link juice” being passed from one URL to another. The more useful question is whether the redirect clearly maps the old URL to an appropriate replacement.
If an old page has backlinks, for example, redirecting it to its genuine replacement allows those links to continue resolving through to the relevant content rather than ending at a 404.
I also try to redirect old URLs directly to their final destination rather than creating chains such as:
URL A → URL B → URL C
Google can follow redirect chains, but recommends redirecting directly to the final destination where possible.
302 redirects
What is a 302 redirect?
A 302 Found response is normally used when a URL is being redirected temporarily.
It tells browsers and search engines that the requested resource is currently available somewhere else, but the original URL hasn’t necessarily been replaced permanently.
That’s the important distinction from a 301:
301 = permanent
302 = temporary
When should you use a 302 redirect?
I’d use a 302 when I genuinely expect the original URL to be used again.
That could include temporarily sending users elsewhere while a page is unavailable, short-term testing or another situation where the redirect isn’t intended to represent a permanent URL change.
If I’ve permanently changed a URL during a website migration or replaced an old page with a new one, I’d normally use a permanent redirect instead.
301 vs 302 redirects
The main difference between a 301 and 302 redirect is whether the move is intended to be permanent or temporary.
A 301 communicates that the original URL has permanently moved. A 302 communicates that the change is temporary.
For normal GET requests, that’s generally the distinction most SEOs and website owners need to care about.
There is another technical difference when redirects involve methods such as POST, however. With a 302, the subsequent request may be changed to GET. If preserving the original request method matters, that’s where a 307 redirect becomes relevant.
303 redirects
What is a 303 redirect?
A 303 See Other redirect tells the client to request another URL using the GET method.
This makes it different from simply saying that a page has temporarily or permanently moved.
A common use is after a form or another POST request. Rather than allowing a refresh to potentially repeat the original submission, the server can return a 303 and send the user to a separate confirmation or results page using GET.
For most SEO migrations and everyday URL changes, 303 isn’t a redirect code I’m likely to use. It’s much more relevant to how web applications handle requests than mapping an old page to a new one.
307 redirects
What is a 307 redirect?
A 307 Temporary Redirect is a temporary redirect that preserves the original HTTP request method and body.
So if the original request was a POST, the redirected request remains a POST.
That’s the important difference between a 307 and a 302: both represent temporary redirects, but a 307 explicitly preserves the request method.
302 vs 307 redirects
For a normal GET request, a 302 and 307 can appear to do essentially the same thing.
The distinction becomes important with other request methods.
A 302 may result in the redirected request being changed to GET, whereas a 307 guarantees that the method and request body are preserved.
So if the redirect is temporary and preserving the request method matters, I’d use a 307 rather than a 302.
308 redirects
What is a 308 redirect?
A 308 Permanent Redirect is a permanent redirect that preserves the original HTTP request method and body.
In that sense, its relationship with a 301 is similar to the relationship between 307 and 302:
301 and 308 are permanent.
302 and 307 are temporary.
The additional distinction is that 307 and 308 guarantee that the original request method and body are preserved.
301 vs 308 redirects
For typical SEO redirects involving normal page requests, both 301 and 308 communicate that the move is permanent, and Google recommends both as permanent server-side redirects.
The technical difference is how the request method is handled. A 308 preserves the original method and body, removing the ambiguity that exists with a 301 for non-GET requests.
I first came across 308 redirects when carrying out a website migration from a WordPress site to the Contentful platform, which appeared to use 308 redirects by default.
I hadn’t really encountered them during my normal SEO migration work before, so I asked John Mueller whether there was any issue with using a 308 rather than a 301. He said it was fine to use either:
301 redirect examples
There are several ways to implement a 301 redirect depending on your server and hosting setup. Below are some common examples for Apache (.htaccess), NGINX and IIS.
Always test redirects after implementing them, particularly when using rules that can affect multiple URLs.
Redirect one old URL to a new URL
htaccess
Redirect 301 /old-url/ https://example.com/new-url/
NGINX
location = /old-url/ {
return 301 https://example.com/new-url/;
}
IIS
<configuration>
<system.webServer>
<httpRedirect enabled="true" destination="https://example.com/new-url" httpResponseStatus="Permanent" />
</system.webServer>
</configuration>
Redirect all pages to the homepage
There are situations where you may genuinely want every URL on a domain to redirect to the homepage – for example, if you’re retiring an old microsite or campaign domain and there are no equivalent pages on the destination site.
I wouldn’t normally use this approach for a website migration where the old pages have relevant replacements. In that situation, individual old URLs should be mapped to their closest equivalent wherever possible.
It’s also worth remembering that redirecting lots of unrelated or removed URLs to the homepage isn’t a reliable way of preserving their SEO value. Google may treat redirects to an irrelevant destination as a soft 404, so this shouldn’t be used simply as a way of avoiding 404 responses.
If redirecting the entire site to the homepage is genuinely the intended behaviour, however, you can do it as follows:
Apache/.htaccess
RewriteEngine On
RewriteRule ^ https://example.com/ [R=301,L]
NGINX
server {
listen 80;
server_name example.com;
return 301 https://example.com/;
}
IIS
<configuration>
<system.webServer>
<httpRedirect enabled="true" destination="https://example.com" httpResponseStatus="Permanent" />
</system.webServer>
</configuration>
Redirect an old domain to a new domain while preserving URLs
These examples preserve the URL path, so /example-page/ on the old domain redirects to /example-page/ on the new domain.
Apache/.htaccess
RewriteEngine on
RewriteRule (.*) https://newdomain.com/$1 [R=301,L]
NGINX
server {
listen 80;
server_name old-domain.com;
return 301 https://newdomain.com$request_uri;
}
IIS
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect old domain to new domain" stopProcessing="true">
<match url="(.*)" />
<action type="Redirect"
url="https://newdomain.com/{R:1}"
redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Redirect www to non-www
Apache/.htaccess
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]
NGINX
server {
listen 80;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
IIS
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to non-www" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www.example.com$" />
</conditions>
<action type="Redirect" url="https://example.com/{R:0}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Redirect non-www to www
Apache/.htaccess
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
NGINX
server {
listen 80;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
IIS
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to www" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^example.com$" />
</conditions>
<action type="Redirect" url="https://www.example.com/{R:0}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Redirect HTTP to HTTPS
Apache/.htaccess
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
NGINX
server {
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
IIS
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
301 redirect generators
If you’re dealing with a large number of redirects, particularly during a website migration, writing every rule manually can become time-consuming and increases the chance of making mistakes.
A 301 redirect generator can help turn a list of old and new URLs into redirect rules for a particular server configuration, such as Apache or NGINX.
I wouldn’t implement generated rules without checking them first. For a large migration, I want to make sure the old and new URLs have been mapped correctly, that the syntax is appropriate for the server configuration, and that the redirects don’t introduce chains or loops.
https://www.rapidtables.com/web/tools/redirect-generator.html
https://www.pixelkicks.co.uk/resources/bulk-301-redirect-generator/
https://salt.agency/tools/bulk-redirect-generator/
https://www.aleydasolis.com/htaccess-redirects-generator/page-to-page/
https://www.danielmorell.com/tools/htaccess/redirect-generator
Bulk 301 redirects
For larger migrations, I normally start with a URL mapping rather than the redirect rules themselves. That gives me a list containing the old URL and its intended destination, which can then be converted into the required redirect format.
For example:
https://oldsite.com/page-a/ → https://newsite.com/page-a/
https://oldsite.com/page-b/ → https://newsite.com/new-page-b/
This is particularly useful when hundreds or thousands of URLs need redirecting, because the important part isn’t simply generating hundreds of 301s – it’s making sure each old URL points to the right destination.
How to check a 301 redirect
Once you’ve implemented a redirect, it’s worth checking that it’s returning the status code you expected and sending users and search engines directly to the correct destination.
For an individual URL, a redirect checker will normally show you the original URL, the HTTP status code returned and the destination URL. This also makes it easy to spot unexpected redirect chains.
https://www.redirect-checker.org/
https://www.whatsmydns.net/redirect-checker
https://www.serpworx.com/check-301-redirects/
https://wheregoes.com/
https://smallseotools.com/redirect-checker/
How to check if a 301 redirect is working
Enter the old URL into a redirect checker and check that it returns a 301 status code followed by the intended destination URL.
Ideally, you want to see something as simple as:
Old URL → 301 → Final URL
Rather than:
Old URL → 301 → URL B → 301 → Final URL
The second example is a redirect chain. It may still get users to the right place, but I’d normally update the original redirect so it points directly to the final URL.
How to check 301 redirects in bulk
Checking redirects individually is fine when you’ve only changed a handful of URLs. During a website migration, however, I normally want to test the entire redirect mapping in bulk.
A crawler such as Screaming Frog can be used to upload or crawl a list of old URLs and check their response codes, redirect destinations and any redirect chains.
For a migration, I’d check that the important old URLs return the expected 301, resolve to the correct final destination and don’t unexpectedly end in a 404, redirect loop or unrelated page.
301 redirect best practices
Redirect to the most relevant destination
A redirect should take users and search engines to the closest equivalent of the original page.
If /old-product/ has been replaced by /new-product/, redirecting directly between those URLs makes sense. Sending it to the homepage simply because the original page no longer exists usually doesn’t.
This is particularly important during website migrations, where accurate URL mapping can make the difference between preserving useful signals and effectively removing pages from the site.
Redirect directly to the final URL
Avoid creating unnecessary redirect chains such as:
URL A → 301 → URL B → 301 → URL C
Where possible, update the original redirect so it goes directly to the final destination:
URL A → 301 → URL C
This reduces unnecessary requests and makes the redirect relationship clearer.
Don’t redirect everything just to avoid 404s
Not every deleted URL needs a redirect.
If a page has been removed and there isn’t a relevant replacement, allowing it to return a 404 or 410 can be more appropriate than redirecting it to an unrelated page.
I generally add a redirect when there’s a genuine replacement or another page that satisfies substantially the same intent.
Avoid redirect loops
A redirect loop occurs when URLs continually redirect between one another, for example:
URL A → URL B → URL A
Users and search engines can’t reach a final destination, so redirect loops should be treated as errors and fixed.
Update internal links where possible
Even if a 301 is working correctly, I prefer to update internal links so they point directly to the final URL rather than relying on the redirect.
For example, don’t leave:
Internal link → old URL → 301 → new URL
when you can change it to:
Internal link → new URL
The redirect can remain in place for external links, bookmarks and previously indexed URLs, but your own website shouldn’t need to use it unnecessarily.
Keep redirects in place after a migration
I wouldn’t remove migration redirects as soon as Google has discovered the new URLs.
Old URLs can continue receiving traffic through backlinks, bookmarks, old emails and other sources long after a migration has taken place.
For important migrated URLs, I generally treat the redirects as part of the site’s ongoing configuration rather than something to remove after a few weeks or months.
Common redirect problems and how to fix them
Redirect chains
A redirect chain occurs when a URL redirects through one or more additional URLs before reaching its final destination.
For example:
URL A → 301 → URL B → 301 → URL C
These often appear over time as URLs are changed more than once. An old redirect might originally have pointed to URL B, but when URL B is later changed to URL C, nobody updates the original rule.
How to fix redirect chains
Where possible, update the redirects so every old URL points directly to the final destination:
URL A → 301 → URL C
URL B → 301 → URL C
I normally look for redirect chains during crawls and when testing redirect mappings for a website migration.
Redirect loops
A redirect loop occurs when redirects send the browser or crawler back to a URL it has already visited.
For example:
URL A → URL B → URL A
You can also create more complicated loops involving several URLs.
The fix is to identify the conflicting redirect rules and make sure there’s a single final destination that doesn’t redirect back into the chain.
Redirects to 404 pages
A redirect can return a perfectly valid 301 status code and still be broken if its destination returns a 404.
For example:
Old URL → 301 → New URL → 404
This can happen when a destination page is subsequently deleted or its URL changes without the older redirect being updated.
When checking redirects, I therefore don’t just check for the initial 301 – I check the final response and destination URL as well.
HTTP and HTTPS redirect chains
A common unnecessary chain is:
http://www.example.com/
→ https://www.example.com/
→ https://example.com/
Where possible, the redirect configuration can instead send the original URL directly to the canonical version:
http://www.example.com/
→ https://example.com/
This is one reason I prefer the redirect examples earlier in this guide to point directly to HTTPS rather than preserving the original $scheme.
www and non-www redirect problems
Problems can occur when different redirect rules are responsible for HTTPS and hostname canonicalisation.
For example, one rule may redirect www to non-www, while another incorrectly redirects the destination back to www, creating a loop.
Choose the hostname you want to use consistently and make sure your redirect rules all point in that direction.
Trailing slash redirects
Trailing slash inconsistencies can also create unnecessary redirects.
For example:
/example → /example/
This isn’t necessarily a problem by itself. The issue is when inconsistent internal links or additional redirect rules create extra hops.
Whichever URL format your site uses, I prefer internal links, canonicals and redirects to point directly to that version.
Which redirect code should you use?
For most SEO work, the choice of redirect comes down to whether the change is permanent or temporary.
If a URL has permanently moved, I’ll normally use a 301 redirect. A 308 is also a permanent redirect and is useful where the original request method and body need to be preserved.
For a temporary change, 302 is the common choice, while 307 guarantees that the original request method and body are preserved.
A 303 has a different purpose and is primarily useful when you want a subsequent request to use GET, such as after a form submission.
Whichever redirect code you’re using, the things I care about most from an SEO perspective are whether it accurately represents the change, points to the most relevant destination, avoids unnecessary chains or loops, and actually works when tested.
And if you’re carrying out a larger website migration, the redirect code itself is only part of the job. Mapping the old URLs to the right destinations and thoroughly testing those redirects is just as important.
If you’re planning a larger move and need help with the redirect strategy, URL mapping or testing, I offer website migration consultancy.
categories
- Analytics Insights
- Crawl Rate Insights
- Ecommerce SEO Insights
- International SEO Insights
- Keyword Research Insights
- Local SEO Insights
- Migrations Insights
- News Insights
- On Page SEO Insights
- Performance Analysis Insights
- SEO Audits Insights
- Site Speed Insights
- Structured Data Insights
- Tag Manager Insights
- Wordpress SEO Insights
latest posts
How To: Track GA4 AI Assistant Traffic, Including Historical Data
A Rough Guide To: LLMS.txt - What It Is & How To Create One
How To: Build SEO Content Hubs for Topical Authority
Case Study: Do Keywords in URLs Help SEO Rankings?
How To: Track Google Business Profile Traffic in GA4
get in touch
If you need some expert website optimisation and configuration, want to find out more, or even just have a question, fill in the form below as I will always be happy to help