/ Redirect Checker Fixes / 302 vs 301

How to Fix 302 vs 301

302 (Found / Temporary) and 301 (Moved Permanently) look similar to users but signal very differently to search engines. 301 tells Google to update the indexed URL and transfer link equity to the new location. 302 tells Google to keep the original URL indexed and treat the target as a temporary stand-in. Sites accidentally using 302 for permanent moves bleed ranking signal and confuse Google about which URL is canonical. This guide covers the distinction, when each is correct, and the config changes per platform.

1. The semantic difference

StatusMeaningLink equityIndex behaviour
301Moved PermanentlyTransferred to targetTarget URL gets indexed, source dropped
302Found (Temporary)Mostly stays with sourceSource URL stays indexed, target seen as alternate
307Temporary (strict method)Mostly stays with sourceLike 302, preserves HTTP method
308Permanent (strict method)Transferred to targetLike 301, preserves HTTP method

2. When to use each

Use 301 (or 308) for permanent moves

Use 302 (or 307) for temporary situations

3. Audit current status codes

Step 1
Redirect Checker scan
Findings group by status code. 302s on permanent paths (post URLs, category URLs, marketing pages) are the priority targets.
Step 2
curl verification
curl -I https://example.com/old-page

# Look for:
# HTTP/2 301 → permanent (correct for moves)
# HTTP/2 302 → temporary (verify intent)
# HTTP/2 307 → strict temporary
# HTTP/2 308 → strict permanent

4. Apache: change 302 to 301

# .htaccess

# Wrong (default Redirect directive defaults to 302)
Redirect /old-page /new-page

# Right — explicit 301
Redirect 301 /old-page /new-page

# Or with RewriteRule
RewriteEngine On
RewriteRule ^old-page/?$ /new-page [R=301,L]

# WRONG (R alone defaults to 302)
RewriteRule ^old-page/?$ /new-page [R,L]

5. nginx: change 302 to 301

server {
  # Wrong: default is 302
  rewrite ^/old-page$ /new-page;
  
  # Right: permanent flag → 301
  rewrite ^/old-page$ /new-page permanent;
  
  # Or with return (preferred for simple redirects)
  location = /old-page {
    return 301 /new-page;
  }
}

6. WordPress

Redirection plugin

Each redirect rule has a "HTTP code" dropdown. Set to "301 - Moved Permanently" instead of "302 - Found".

Plugin → Redirection → Redirects → edit each rule:
  HTTP code: 301 Moved Permanently  (was 302)

Yoast SEO Premium / Rank Math redirects

Similar dropdown per redirect. Default to 301 unless temporary.

functions.php for canonical redirect

add_action('template_redirect', function() {
  if (is_page('old-slug')) {
    wp_redirect(home_url('/new-slug/'), 301);  // explicit 301
    exit;
  }
});

7. Framework-specific patterns

Express.js

// Wrong: default is 302
app.get('/old-page', (req, res) => {
  res.redirect('/new-page');
});

// Right: explicit 301
app.get('/old-page', (req, res) => {
  res.redirect(301, '/new-page');
});

Django

from django.http import HttpResponsePermanentRedirect, HttpResponseRedirect

# Wrong: 302
return HttpResponseRedirect('/new-page')

# Right: 301
return HttpResponsePermanentRedirect('/new-page')

# Or in urls.py
from django.views.generic import RedirectView
path('old-page', RedirectView.as_view(url='/new-page', permanent=True))

Next.js

// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/old-page',
        destination: '/new-page',
        permanent: true,  // → 308 (modern permanent)
      },
      {
        source: '/temp-redirect',
        destination: '/somewhere',
        permanent: false,  // → 307 (modern temporary)
      }
    ];
  }
};

8. Cloudflare

Cloudflare → Rules → Bulk Redirects (or Page Rules)

For each redirect:
  Source URL: example.com/old-page
  Target URL: https://example.com/new-page
  Status code: 301 (Moved Permanently)  ← not 302
  Preserve query string: Yes

9. Common mistake patterns

Mistake 1: 302 from default config

Many framework redirect helpers default to 302. Always check and explicitly set 301 for permanent moves. Don't assume the framework picked the right code.

Mistake 2: 302 for A/B test that becomes permanent

A/B test runs for 6 months, winner adopted permanently. 302 left in place. Google still favours the test source URL in search. Once the test concludes, change to 301 for the winning variant.

Mistake 3: 302 then immediate 301

# Wrong chain
/old-page → 302 → /interim → 301 → /new-page

# The 302 loses equity that the 301 then partly recovers.
# Fix: collapse to one hop
/old-page → 301 → /new-page

10. Verify after the fix

Step 1
Status code confirmation
curl -I https://example.com/old-page | grep -i "^HTTP"
Should show HTTP/2 301 (or HTTP/2 308 for modern strict).
Step 2
Search Console crawl request
Submit the old URL for re-crawl. Google processes the 301, transfers signals to the new URL over 2-8 weeks. Track via Search Console Performance — impressions and clicks for the new URL should rise as the old one drops.
💡 If you're not sure whether a redirect is permanent or temporary, ask: will the original URL ever serve content again? If no, it's permanent — use 301/308. If maybe later (A/B test, geo, maintenance), it's temporary — use 302/307. When uncertain, 301 is the safer default for SEO.

↪️ Re-run the Redirect Checker

Verify status codes match intent.

Run Redirect Checker →
Related Guides: Redirect Checker Fixes  ·  Fix Redirect Chains  ·  Fix HTTPS Redirects  ·  Redirect Checker Guide
💬 Got a problem?