301 vs 302 redirect: what does each code tell Google?
Each code is a short statement of intent. A 301 says the page has a new address and isn't coming back. A 302 says it's somewhere else for now. Google reads that statement when it decides which URL to keep, and it matters most during a move, when hundreds of old addresses have to hand their place in results to their replacements. That's where most of my site migration SEO help goes.
Google's redirects documentation is plain about it. With a permanent redirect, Googlebot follows it and the indexing pipeline uses it as a signal that the target should be canonical. With a temporary one, Googlebot still follows it, but the pipeline doesn't use it as that signal. Google's page on HTTP status codes calls the 301 a strong signal and the 302 a weak one. Weak isn't zero, and strong isn't a promise: Google weighs redirects alongside canonical tags and sitemaps, and it can still pick a different canonical than the one you'd like.
The worst redirect is the one that's missing. On one WooCommerce store, daily clicks fell from 162 to 49 in three days after a redesign changed URLs without mapping the old ones to the new, and they came back once each old URL had a 301 to its closest new page.
| Code | What it says | How Google treats it | When I use it |
|---|---|---|---|
| 301 Moved Permanently | The page has a new permanent address | A strong signal the target should be canonical; the target shows in results | Renamed pages, merged pages, domain and URL moves |
| 308 Permanent Redirect | Same as a 301, and the request method is kept | Equivalent to a 301 | Fine when a server or CDN sends it |
| 302 Found | The page is somewhere else for now | A weak signal; the source page shows in results | A page that's coming back |
| 307 Temporary Redirect | Same as a 302, and the request method is kept | Equivalent to a 302 | The same short-term cases as a 302 |
| 303 See Other | Fetch a different resource instead | Treated as temporary, like a 302 | Almost never for a page that should rank |
Two other kinds turn up on WordPress sites. An instant meta refresh, set to 0 seconds, is read as permanent, and a delayed one as temporary. A JavaScript redirect is the last resort, because Google only sees it if the page renders. So when I audit redirects, I read the status code in the response headers, not a plugin screen that says a redirect exists.
When should I use a 301 vs a 302?
Use a 301 for anything permanent and a 302 only when the old URL is coming back. My test is a single question: is it coming back? If the honest answer's yes, and soon, a 302 fits. If it's no, or nobody knows, it's a 301.
Google's own example of a temporary redirect is a service that's unavailable for a while, where you send visitors to a page that explains what's happening. Its testing guidance adds another: when a test sends visitors from the original URL to a variant, use a 302, not a 301, and remove the test once it's done. A seasonal page that's switched off until next year goes in the same bucket.
What I don't use a 302 for is a permanent change dressed up as a temporary one, and the usual culprit is a default nobody changed. WordPress's own wp_redirect() function sends a 302 unless the code passes another status, so a custom snippet that moves pages for good can quietly send the temporary code. The browser lands in the same place either way, so nobody notices.
If a 302 has sat on a page that's never coming back, I change it to a 301. And a deleted page with nothing close to replace it doesn't get a redirect of either kind; sending it to the homepage only hides the dead end.
Check the code, not the destination. Clicking an old link only shows where it lands. curl -I on the old URL prints the status line, and in Chrome DevTools the Network panel's Status column shows each hop's code, with Preserve log ticked so nothing clears between page loads. That code is the part Google reads.
301 vs 302 redirect caching: does a browser remember a 301?
It can, and a 302 usually isn't remembered at all. The HTTP standard, RFC 9110, says "A 301 response is heuristically cacheable", and it gives the 308 the same line. Neither 302 nor 307 is on that list, so a browser only stores one when the server sends explicit cache headers for it.
That matters most while you're testing. A browser that's saved a 301 can skip the server and go straight to the new address, so if you publish a 301 to the wrong page and then fix it, your own browser may keep following the old rule while everyone else gets the new one. I test unsure targets with the cache disabled, and I check the code from the command line before I call it done.
Rather have me do this? One person, whole job.
Book a call on UpworkWhat's a redirect chain, and how do I find them?
A chain is one URL passing through more than one redirect before it reaches a page. A to B to C is a chain of two hops. Google's crawlers follow up to 10 hops by default, so a short chain usually still gets there, but Google's site move guidance still advises redirecting to the final destination directly. Every extra hop is another request for the browser and for Googlebot, and another rule that can break.
Chains pile up one sensible change at a time. Take an address first published before the site had HTTPS. Later the domain changed, and later still a restructure moved posts under /blog/. A link on another site still points at the oldest version, so it goes HTTP to HTTPS, old domain to new, old path to new path. That's three hops, each added by someone doing their job properly.
When a chain runs too long or loops, Search Console lists the URL under Redirect error in the Page indexing report. Old URLs showing as Page with redirect are normal: Google describes them as non-canonical URLs that redirect elsewhere, so they aren't indexed themselves. It's the Redirect error rows that need work, and when new URLs won't index for other reasons, that's a separate crawl and indexing diagnosis.
To find chains before Google does, I run the old URLs through a crawler in list mode with redirects followed, then sort by hop count. The list comes from the same places as the URL list for a Wix to WordPress move. For a spot check, curl -sIL on one URL prints every hop and its status in order.
Where should a redirect live: server, plugin or CDN?
Any of the three can send a proper 301. Google recommends server-side redirects because they've got the highest chance of being read correctly, and all three count: Googlebot gets a status code and a new location before any page content. So the real question is which layer the person running the site can see and keep tidy.
| Where | How it's set | What I watch for |
|---|---|---|
| Web server | Apache's .htaccess with mod_alias or mod_rewrite, or NGINX return and rewrite rules | Fast and independent of WordPress, but easy to lose on a host move |
| WordPress plugin | A redirect manager in the dashboard, or code that calls wp_redirect() | Easy to see and edit; the code route defaults to 302 unless a status is passed |
| CDN | Edge rules such as Cloudflare's Single Redirects or Bulk Redirects | Cloudflare defaults to 301, but nobody editing WordPress can see these rules |
My rule is one layer per job. Site-wide rules, like HTTP to HTTPS and one hostname over the other, go in one place, usually the server or the CDN. Page moves go in one list, usually a plugin, so whoever runs the site can see them. A split setup is where chains breed: a CDN rule adds the www, the server adds the trailing slash, a plugin moves the page, and each layer's owner only sees their own hop.
How I flatten redirect chains after a migration
This is the order I work in once a move has settled, or when an audit turns up chains left from old moves. The aim: every old URL answers with one redirect, straight to a page that returns 200.
- Step 01
Put every rule from every layer in one sheet
I export the plugin's redirect list, read the server config and list the CDN rules. Until they sit side by side, nobody can see a URL's whole path.
- Step 02
Add every old URL that still gets requests
The Search Console export by page, the old sitemaps and a backlink export add the addresses that links and bookmarks still use, including ones no rule covers yet.
- Step 03
Trace each URL to its final answer
The crawler records every hop, each status and where the path ends. A final 404, a loop or a path through the homepage goes on the fix list.
- Step 04
Point every rule at the final address
If A goes to B and B goes to C, A's rule changes to go straight to C. B keeps its own rule to C, because B may have links of its own.
- Step 05
Fix the ends that don't land
A target that now 404s gets its closest live replacement. If nothing's close, the old URL returns a 404 or 410, not a redirect to something unrelated.
- Step 06
Use the permanent code on every permanent move
Any 302 left behind by a code default or a quick fix becomes a 301, unless the page is actually coming back.
- Step 07
Stop linking to redirects
Menus, internal links, canonical tags and the XML sitemap get the final URLs. Google's move guidance says to update internal links, and it treats every sitemap URL as a suggested canonical, so a redirecting URL doesn't belong there.
- Step 08
Re-run the list, then leave the rules alone
Every URL should now take one hop to a 200. Google's advice for a move is to keep redirects for as long as possible, generally at least a year, and I keep them longer when old addresses still have links.
If your site's been through two or three moves and nobody's sure which layer does what, that clean-up is part of the migration work I do, remotely and from the search side. The build stays with your developer.
Book a call on Upwork
