You moved a page, renamed a URL or switched domains. Now you need to send people and Google to the new address. The short answer to the 301 vs 302 redirect question: use a 301 when the move is permanent, and a 302 when the old URL will come back. In the rest of this guide I explain why that choice matters and how to set it up without losing traffic.
The status code is a message to Google about which URL to show in search results. Pick the wrong one and the wrong URL can stay indexed for months.
What a Redirect Actually Tells Google
A server-side redirect is an HTTP response with a 3xx status code and a Location header that points to the new URL. Browsers follow it instantly. Googlebot follows it too. Then it has to decide which of the two URLs is the “real” one.
That decision is called canonicalization (picking the main version of a page). Google keeps track of both the old and the new URL. One becomes the canonical version that appears in results. The other becomes an alternate name that can still show up for some searches.
The redirect type is one of the strongest hints Google uses to make that call. Google’s documentation on redirects says permanent redirects tell Google the target should become canonical. Temporary redirects tell it the source page may stay in results.
Permanent vs Temporary: The Status Codes
There are five status codes you’ll come across. Google puts them into two families.
Permanent Redirects: 301 and 308
- 301 Moved Permanently is the standard choice for any lasting URL change.
- 308 Permanent Redirect means the same thing. But it tells clients they must keep the original request method. A form POST stays a POST instead of turning into a GET.
Google treats 301 and 308 the same way. Both are a strong signal that the target URL should be the canonical one.
Temporary Redirects: 302, 303 and 307
- 302 Found is the classic temporary redirect. It’s the default in many frameworks and plugins.
- 303 See Other is mostly used after someone submits a form, to send the browser to a results or confirmation page.
- 307 Temporary Redirect is the method-keeping version of 302, in the same way 308 relates to 301.
Google treats these as a weak signal. It still follows them to the target. But it doesn’t treat the target as canonical by default, so the original URL usually stays in the index.
For search, 307 and 302 behave the same. The codes still mean different things, though. Google recommends using the one that matches your intent, so browsers and other tools also behave correctly.
301 vs 302 Redirect: What Changes in Search
Here is how the two families compare in practice.
| Question | 301 / 308 (permanent) | 302 / 303 / 307 (temporary) |
|---|---|---|
| Which URL usually appears in results? | The new URL | The old URL |
| Signal strength for canonical selection | Strong | Weak |
| Where link signals tend to consolidate | The new URL | Usually the old URL |
| Browser caching | Often cached, sometimes for a long time | Generally not cached unless headers say so |
| Typical use | Moves, merges, HTTPS, domain changes | Short promotions, maintenance, tests |
Two finer points matter here.
First, redirects are signals, not commands. Google weighs them next to internal links, sitemaps and rel="canonical". If your redirect says one thing and everything else on the site says another, Google may pick a canonical you didn’t expect.
Second, Google can reread a redirect that looks wrongly labelled. A 302 that stays in place for a long time and never changes can end up treated like a permanent move. You can’t predict when that happens, so don’t rely on it. Use the right code from the start.
On link value: Google has said for years that 3xx redirects don’t lose PageRank. The real risk with a 302 isn’t “lost link juice”. It’s the wrong URL staying canonical.
Meta Refresh and JavaScript Redirects
Sometimes you can’t touch the server, for example on a locked-down hosted platform. Google supports two browser-side fallbacks, with some limits.
Meta Refresh
A meta refresh is a tag in the page’s <head>, or an HTTP Refresh header, that tells the browser to load another URL.
<meta http-equiv="refresh" content="0; url=https://www.example.com/new-page/">
The delay value decides how Google reads it:
- Instant (0 seconds): treated as a permanent redirect.
- Delayed (1 second or more): treated as a temporary redirect.
Delayed refreshes also confuse visitors, who see one page flash before another loads. If you must use meta refresh, use a 0-second delay.
JavaScript Redirects
A JavaScript redirect changes window.location after the page loads.
<script>
window.location.replace("https://www.example.com/new-page/");
</script>
Google can handle these, but only after it renders the page (runs its code like a browser). Rendering happens after crawling and can fail. If it fails, Google never sees the redirect. Google’s advice is to use JavaScript redirects only when server-side and meta refresh options aren’t available. I’d treat them as a last choice too.
Using location.replace() instead of setting location.href keeps the old URL out of the visitor’s back-button history. So they don’t get bounced forward again when they press Back.
The Last Resort: A “We’ve Moved” Page
If you can’t redirect at all, a page with a clear link to the new URL and a short note helps visitors. Google calls this a crypto redirect and may or may not treat it as a redirect. So treat it as a stopgap and ask your host about real options.
When to Use Which Redirect
I ask one question: will the old URL ever show its own content again? If the answer is no, use a permanent redirect.
Use a 301 (or 308) When
- You change a URL slug, folder structure or file extension.
- You move from HTTP to HTTPS, or between www and non-www.
- You move to a new domain or rebrand.
- You merge two thin or overlapping articles into one stronger page. This is a common fix when pages compete for the same search, covered in my guide to fixing keyword cannibalization.
- You stop selling a product and have a close replacement.
- You combine duplicate URLs, such as trailing-slash versions. See how Google handles duplicate content for the wider picture.
Use a 302 (or 307) When
- A product is out of stock for now and you want to send shoppers to a category page for a few weeks.
- You’re running a short seasonal campaign and want a URL to point to a promo page.
- A page is under maintenance and will come back at the same address.
- You’re testing a new page design and the original URL should keep its ranking.
- You send logged-out users to a login page and back again.
Here’s an example. An online shop moves its “Winter coats” category from /winter-coats/ to /womens/coats/ during a redesign. That’s permanent, so it’s a 301. The same shop sends /gift-guide/ to a Black Friday landing page for two weeks, then switches it back. That’s a 302.
When Not to Redirect at All
If a page is gone and there’s no truly related replacement, return a 404 or 410. Pointing hundreds of unrelated old URLs at your home page doesn’t keep rankings. Google warns that sending many old URLs to one unrelated page can confuse users and may be treated as a soft 404 (a page Google sees as “not found” even though it loads).
Setting Up Redirects: Server Examples
Server-side redirects are the most reliable kind. Here’s how to set them up on the most common setups. Replace example.com and the paths with your own. I always test on a staging copy first.
Apache (.htaccess)
For a single page, mod_alias is the simplest option:
# Permanent redirect for one page
Redirect 301 /old-page/ https://www.example.com/new-page/
# Temporary redirect for a promotion
Redirect 302 /gift-guide/ https://www.example.com/black-friday/
For patterns, use mod_rewrite. This sends every HTTP and non-www request to the HTTPS www version in a single hop:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www. [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
Note that [R] on its own means a 302. Always write R=301 when you mean permanent.
Nginx
Nginx uses return for simple cases:
# One page, permanent
location = /old-page/ {
return 301 https://www.example.com/new-page/;
}
# Whole site from HTTP to HTTPS www
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
For pattern-based rules, rewrite with the permanent flag gives a 301. The redirect flag gives a 302:
rewrite ^/blog/(.*)$ /articles/$1 permanent;
WordPress
Most WordPress sites manage redirects with a plugin such as Redirection, or the redirect manager built into some SEO plugins. Check the default type when you create a rule, because some tools default to 302. In my experience, this is where most accidental 302s come from.
WordPress core also redirects many posts on its own when you change their slug. But don’t depend on that for bigger structural changes.
If you prefer code, add this to a small custom plugin or your child theme’s functions.php:
add_action( 'template_redirect', function () {
$path = trim( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '/' );
if ( 'old-page' === $path ) {
wp_safe_redirect( home_url( '/new-page/' ), 301 );
exit;
}
} );
The second argument to wp_safe_redirect() sets the status code. Leave it out and WordPress sends a 302. The exit stops the rest of the page from loading.
Redirect Chains and Loops
A chain is when URL A redirects to B, and B redirects to C. Chains build up quietly over years of redesigns, HTTPS moves and slug changes.
By default, Google’s crawlers follow up to 10 redirect hops. That sounds like a lot. But each hop adds a delay for visitors, costs crawlers an extra request, and adds another place for something to break. Google’s site move advice says to redirect straight to the final page. Where that isn’t possible, keep chains short: ideally no more than 3 hops and fewer than 5.
A typical chain looks like this:
http://example.com/shoes
-> 301 https://example.com/shoes
-> 301 https://www.example.com/shoes
-> 301 https://www.example.com/shoes/
The fix is to update the original rule so it points straight at https://www.example.com/shoes/. Where your server allows it, combine protocol, host and trailing-slash rules into one redirect.
A loop is when A redirects to B and B redirects back to A. Browsers show a “too many redirects” error, and Google can’t reach any content. Loops usually come from two rules that fight each other. For example, a plugin adds a trailing slash while the server removes it.
On large sites, chains also waste crawl requests that could go to real pages. If that worries you, read my explainer on when crawl budget matters.
How Long to Keep Redirects in Place
Longer than you think. Google’s site move documentation recommends keeping redirects for as long as possible, generally at least one year. Old URLs live on in bookmarks, emails, PDFs and other sites’ links long after Google has updated its index. My own habit is to leave important redirects in place for good.
For a domain move, that means keeping the old domain registered and the redirect server running. If the old domain lapses, every inbound link that still points to it breaks.
Once the redirect is live, finish the job:
- Update internal links to point straight at the new URLs.
- Update your XML sitemap so it lists only final URLs.
- Update
rel="canonical"tags, hreflang tags and structured data that still use old addresses. - Ask the owners of your most valuable backlinks to update them where it makes sense.
Don’t panic if old URLs still show up in results for a while after a move. Google says this can happen and usually fades on its own.
Testing Redirects With Curl and URL Inspection
Don’t test redirects only in your browser. Browsers cache (save) permanent redirects. So after an edit, you may keep seeing the old behaviour even though the server has changed. Use tools that show the raw response.
Check the Status Code With Curl
This shows only the headers for a single request:
curl -I https://www.example.com/old-page/
Look for the status line, such as HTTP/1.1 301 Moved Permanently, and the Location header with the target URL.
To follow every hop and spot a chain, add -L:
curl -sIL https://www.example.com/old-page/ | grep -iE "^(HTTP|location)"
Each HTTP line is one response. If you see more than one 3xx before the final 200, you have a chain.
For a one-line summary per URL, which is handy when checking a list:
curl -s -o /dev/null -w "%{http_code} %{redirect_url}n" https://www.example.com/old-page/
One warning: -I sends a HEAD request, and a few servers answer HEAD differently from GET. If the result looks odd, drop -I and use -sL -D - -o /dev/null instead. That prints the headers of a normal GET.
Check How Google Sees It in Search Console
The URL Inspection tool in Search Console shows Google’s view.
- Inspect the old URL. Once Google has processed the redirect, it should say the page isn’t indexed because it is a page with redirect.
- Inspect the new URL. Check that it’s indexed and that the Google-selected canonical is the new URL itself.
- Use the live test on the new URL to confirm Googlebot can fetch it with a 200 response.
Weeks after a 301 went live, is the Google-selected canonical on the new URL still the old address? Then look for mixed signals: internal links, sitemaps or canonical tags that still point to the old URL. That’s the first thing I check. My beginner’s guide to Search Console walks through the reports you’ll use for this.
For bigger migrations, a site crawler that reports status codes for every URL in your old sitemap is the quickest way to catch broken rules, chains and accidental 302s in one go.
Common Redirect Mistakes
- Using 302 by accident for a permanent move. Many plugins, frameworks and CMS settings default to 302. Check every new rule with curl.
- Redirecting everything to the home page. It looks tidy but is often treated as a soft 404, and it annoys visitors.
- Removing redirects after a few weeks. Old links keep arriving for years.
- Leaving internal links on old URLs. Every internal click then goes through a redirect, and you send Google mixed canonical signals.
- Redirecting to a page that’s blocked or broken. A redirect to a URL that returns 404, or is blocked in robots.txt, passes nothing useful.
- Stacking rules in several places. Rules in the CDN, the server config and a WordPress plugin can clash and create chains or loops. I keep redirects in as few places as I can.
Conclusion
The 301 vs 302 redirect choice comes down to intent. If the old URL is gone for good, use a 301 or 308 so Google moves the canonical to the new address. If it will come back, use a 302 or 307 so the original keeps its place.
Use server-side redirects where you can, and point every rule straight at the final URL. Keep redirects for at least a year, and check the result with curl and URL Inspection. As a next step, crawl your site for 3xx responses and fix any chains or accidental 302s you find.



