Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

SEO & Digital Marketing  Module 2 – Technical SEO: crawling and indexing

Redirects, status codes and soft 404s

Choose 301, 308, 302 or 307 for a moved page, collapse redirect chains, answer 404 or 410 for pages that are gone, and pause a site safely with 503.

  • Intermediate
  • 20 minutes
  • Examples run with Node.js 24.21.0, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free lesson, Pro answers: 20 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Choose 301, 308, 302 or 307 for an address that changes, and say how Google treats each
  • Find redirect chains and loops in a redirect map, and send every old address to its page in one hop
  • Answer pages that are gone with 404 or 410, and recognise a soft 404
  • Plan a maintenance pause with 503 and Retry-After while robots.txt keeps answering 200

Before you start

What you’ll learn · Before you start

What you will learn

  • Choose 301, 308, 302 or 307 for an address that changes, and say how Google treats each
  • Find redirect chains and loops in a redirect map, and send every old address to its page in one hop
  • Answer pages that are gone with 404 or 410, and recognise a soft 404
  • Plan a maintenance pause with 503 and Retry-After while robots.txt keeps answering 200

Before you start

On this page

Pune Bakes moved its menu twice in a year, and an old link to its mango cake now passes three redirects before it reaches the page. Every visit through that link costs four requests, and one wrong rule in the redirect map sends visitors round in a loop that never reaches a page at all.

A redirect is one of the answers a server gives, and each answer’s status code tells Google something different about an address: here, moved, gone or busy. By the end of this page you can choose between 301, 308, 302 and 307, clean a redirect map so that every old address reaches its page in one hop, answer pages that are gone with 404 or 410 instead of a soft 404: A page that says something is missing, or holds almost nothing, while its status code says 200. Search Console reports it as a soft 404; a missing page should answer 404 or 410., and pause a site for maintenance without hurting how Google crawls it.

Every answer starts with a status code, and Google acts on it

An HTTP response starts with a three-digit status code: The three-digit number at the start of every HTTP response that says what happened: 2xx success, 3xx a redirect, 4xx a client error such as 404, 5xx a server error. Google's crawlers act on it before they read the page., whose first digit gives its class: 2xx success, 3xx redirection, 4xx a client error, 5xx a server error (RFC 9110, section 15). Google’s crawlers read the code before they read the page, and they treat the common codes like this (HTTP status codes and Google Search):

Code What Google’s crawlers do
200 Pass the content on to indexing: the page is a candidate, with no promise that it is kept
301, 308 Follow the redirect; a strong signal that the target is the canonical
302, 303, 307 Follow the redirect; a weak signal
404, 410 and every other 4xx but 429 Treat the content as missing: not indexed, and an indexed address is removed over time
429, 500, 502, 503 Slow down crawling for a while; indexed pages are kept at first, then dropped if the errors go on

Whatever a redirecting or failing answer contains is ignored, so a helpful message in a 404 page is for visitors only. Step through five of the bakery’s addresses, each answering with a different family of code:

Interactive · step by step What Googlebot does with each answer Step through five of the bakery's addresses, each answering with a different family of status code.
What Googlebot does with each answer, step 6 of 6. Showing Googlebot fetches, 200: page goes on, 301 or 308: moved, 302 or 307: for now, 404 or 410: not there, 429 or 5xx: slow down. In focus: 429 or 5xx: slow down.Googlebot fetches200: page goes on/cakes/mango-mousse301 or 308: moved/menu/mango-cake302 or 307: for now/offers/404 or 410: not there/cakes/plum-cake429 or 5xx: slow downthe whole siteGET /, 503

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Before the page, the code. Every answer starts with a three-digit status code. Googlebot reads it before anything else, and it decides what happens to the address in Google's index.
  2. 200: the page goes on. The mango mousse page answers 200. Its content goes on to indexing, which may still decide not to keep it; a 2xx makes a page a candidate, nothing more.
  3. 301 or 308: moved for good. The old menu address answers 301 with a Location. Googlebot follows it, up to 10 hops, ignores whatever the redirecting answer contained, and takes the move as a strong signal that the target is the canonical.
  4. 302 or 307: moved for now. The offers page points to this week's festival offer with a 302. Googlebot follows it, but a temporary redirect is a weak signal, so the source address usually stays in results.
  5. 404 or 410: not there. The plum cake is gone and its page answers 404. Every 4xx but 429 tells Google the content does not exist, so an indexed address is removed, and Google crawls it less and less often.
  6. 429 or 5xx: slow down. During an overload the server answers 503. Google's crawlers slow down for a while and keep indexed pages at first, but addresses that keep failing are dropped in the end. A 429 counts the same way.

The codes differ in meaning even where Google handles two of them alike, as it does 301 and 308, so choose the one that says what happened: other search engines and other readers of the web use them too.

HTTP Status Codes Reference Look up any status code: what it means, why a server sends it and how to fix it.

Checkpoint

Check: What each status code tells Google

  1. Question 1 of 2 A page answers 200. What does that tell you about Google's index?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The page goes on to indexing as a candidate, with no promise that it is kept

    200 lets a page in; what happens next depends on the page, its duplicates and Google's other systems.

  2. Question 2 of 2 The bakery's 404 page lists its twelve bestsellers with links. What does Google do with that content?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It ignores it; the content of a 4xx answer is for visitors only

    Keep the helpful links for people, and let the status code speak to Google.

A permanent redirect moves the address Google shows; a temporary one keeps it

Google treats a redirect as a signal about which address should be canonical, and the difference between the two kinds is the address people see in results (Redirects and Google Search). A permanent redirect: A redirect with status 301 or 308, or an instant meta refresh, that says the content has moved for good. Google treats the target as canonical and shows it in results. makes Google show the target; a temporary redirect: A redirect with status 302, 303 or 307, or a delayed meta refresh, that says the move will be undone. Google follows it but usually keeps showing the source address in results. makes it keep showing the source, although the target may still be indexed if other signals point at it. Google lists the methods in the order in which it interprets them most reliably:

Method Permanent Temporary
Server-side HTTP redirect 301, 308 302, 303, 307
meta refresh: An HTML meta element with http-equiv="refresh" that sends the browser to another address after a delay. Google treats a delay of 0 seconds as a permanent redirect and a longer one as temporary., or the HTTP Refresh header Instant, a delay of 0 seconds A delay of more than 0 seconds
JavaScript location Only if nothing above is possible Not listed
A link with a note that the page has moved A last resort Not listed

Google’s advice is to “use a permanent server-side redirect whenever possible”. A JavaScript redirect works only if Google renders the page successfully, so it comes after both of those, and a link with a note comes last of all. The pairs differ in one more way, which matters for forms: when a browser follows a 301 or a 302 it may turn a POST into a GET, losing the form’s data, while 307 and 308 forbid any change of method (RFC 9110, sections 15.4.2 to 15.4.9). Google treats 308 like 301 and 307 like 302.

After a permanent move Google keeps the old address for a while as an alternate name of the new one, and may still show it when a search hints that people trust the old address more; such names fade away without any action. On Apache the simplest rule is Redirect permanent "/one" "https://punebakes.example/two"; on Nginx it is return 301 inside a location.

Key idea

Choose the redirect by what should show in results: a permanent one, 301 or 308, for a move that will not be undone, and a temporary one, 302 or 307, for a move that will; and 308 or 307 when forms post to the address.

Checkpoint

Check: Permanent or temporary redirects

  1. Question 1 of 2 For the seven days of the festival, /offers/ points to /offers/holi/. Which redirect fits?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 302, so that /offers/ stays the address in results

    A temporary move gets 302 or 307; when the festival ends, the redirect comes off and /offers/ shows its own page.

  2. Question 2 of 2 The order form moved to a new address for good, and partner sites' forms still send POST requests to the old one. Which redirect fits?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 308, permanent and keeping the POST a POST

    The pairs differ in two ways: permanent or temporary, and whether the method may change.

Chains and loops: every old address reaches its page in one hop

A redirect chain: Two or more redirects in a row, A to B to C. Google's crawlers follow up to 10 hops, but every hop costs visitors a request, so old addresses should point straight at the final page. grows a rule at a time: each move adds one, and nobody goes back to point the older rules at the newest address. Google’s crawlers follow up to 10 hops by default (HTTP status codes and Google Search), but every hop costs each visitor one more request, and Google’s site-move guide asks for no chains at all, redirecting “to the final destination directly”, or at least “ideally no more than 3 and fewer than 5” hops (How to move a site). Follow the old link to the mango cake:

Interactive · message by message Three hops for one old link Step through an old link to the mango cake, written with http and the old menu folder, as Googlebot follows it.
Three hops for one old link, step 6 of 6. Messages so far: Googlebot to The bakery's server: GET http /menu/mango-cake; Googlebot to The bakery's server: GET /menu/mango-cake; Googlebot to The bakery's server: GET /cakes/mango-cake; The bakery's server to Googlebot: 200 /cakes/mango-mousse; Googlebot to The bakery's server: GET http /menu/mango-cake.GooglebotThe bakery's serverGET http /menu/mango-cakeGET /menu/mango-cakeGET /cakes/mango-cake200 /cakes/mango-mousseGET http /menu/mango-cakeone 301 to the final page

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. An old link. A food blog still links to http://punebakes.example/menu/mango-cake, an address from before the bakery's move to HTTPS and to the new folders.
  2. Hop 1, the protocol. The http host sends every request to the same path on https with a 301.
  3. Hop 2, last year's move. The https host has last year's rule for the old menu folder and answers 301 to /cakes/mango-cake.
  4. Hop 3, this month's rename. The cake was renamed this month, so /cakes/mango-cake answers 301 to /cakes/mango-mousse.
  5. The page, at last. The fourth request gets 200. Googlebot follows up to 10 hops by default, so it arrives, but every visitor's browser made the same four requests to get there, one after another.
  6. One hop. The fix sends every old address straight to its final address. With full https targets in the rules of both hosts, the old http link reaches the page after a single 301.

A redirect loop: Redirects that lead back to an address already passed, A to B to A, so no page is ever reached. Browsers stop with an error, and Search Console reports a redirect error. is worse: it never reaches a page at all, and the Page indexing report lists such addresses under “Redirect error”, with a chain too long, a loop, an address that grew past the maximum length and a bad or empty address as its causes (Page indexing report). Here is the bakery’s redirect map as the server holds it, last year’s move and this month’s renames together:

redirect_map.csv: every redirect the server has today CSV · redirects/redirect_map.csv
old,new
/menu/mango-cake,/cakes/mango-cake
/menu/choco-truffle,/cakes/choco-truffle
/menu/red-velvet,/cakes/red-velvet-heart
/menu/rasmalai,/cakes/rasmalai-cake
/menu/black-forest,/cakes/black-forest
/menu/pineapple,/cakes/pineapple-cake
/menu/butterscotch,/cakes/butterscotch-cake
/menu/coffee-walnut,/cakes/coffee-walnut
/menu/plum-cake,/cakes/plum-cake
/menu/blueberry,/cakes/blueberry-cheesecake
/menu/fruit-cake,/cakes/fruit-cake
/menu/,/cakes/
/menu/cupcakes,/cupcakes/
/menu/brownies,/brownies/
/menu/cookies,/cookies/
/menu/breads,/breads/
/cakes/mango-cake,/cakes/mango-mousse
/cakes/choco-truffle,/cakes/eggless-truffle
/about-us,/about/
/contact-us,/contact/
/offers,/offers/diwali
/offers/diwali,/offers
/order-online,/order/
/gift-hampers,/hampers/

The program follows each old address to where the map finally sends it, using the 20 addresses that answer 200, and writes the rules again for Apache and Nginx:

The redirect map, cleaned and written for two servers Python · redirects/redirect_map.py
"""Clean Pune Bakes' redirect map, then write it as Apache and Nginx rules.

redirect_map.csv holds every redirect the bakery's server has today: those of last year's move from /menu/ to the
new folders, and this month's renames. LIVE lists the addresses that answer 200. The program follows
each old address to where the map finally sends it, points it there in one hop, and reports chains, loops and redirects
to pages that no longer exist. It writes redirects.conf (Apache) and redirects-nginx.conf (Nginx), with full https
targets, so that the same rules on the http host also send old links to the final page in one hop.
"""

import csv

SITE = "https://punebakes.example"

LIVE = {  # the addresses that answer 200, from a crawl of the site
    "/cakes/", "/cakes/mango-mousse", "/cakes/eggless-truffle", "/cakes/red-velvet-heart", "/cakes/rasmalai-cake",
    "/cakes/black-forest", "/cakes/pineapple-cake", "/cakes/butterscotch-cake", "/cakes/coffee-walnut",
    "/cakes/blueberry-cheesecake", "/cakes/fruit-cake", "/cupcakes/", "/brownies/", "/cookies/", "/breads/",
    "/about/", "/contact/", "/offers/", "/order/", "/hampers/",
}

rules = {row["old"]: row["new"] for row in csv.DictReader(open("redirect_map.csv", encoding="utf-8"))}


def follow(address):
    """The addresses the map sends `address` through, ending where it stops or where a loop begins again."""
    path = [address]
    while path[-1] in rules:
        nxt = rules[path[-1]]
        if nxt in path:
            return path + [nxt], True
        path.append(nxt)
    return path, False


chains, loops, gone, final = [], {}, [], {}
for old in rules:
    path, loop = follow(old)
    if loop:
        loops.setdefault(frozenset(path), path)  # each loop once, from the first address that enters it
    elif path[-1] not in LIVE:
        gone.append(path)
    else:
        final[old] = path[-1]
        if len(path) > 2:
            chains.append(path)

print(f"{len(rules)} redirects read, {len(LIVE)} live pages")
print(f"{len(chains)} chains, each now one hop:")
for path in chains:
    print("  " + " -> ".join(path))
print(f"{len(loops)} loop, left out until someone decides where it should go:")
for path in loops.values():
    print("  " + " -> ".join(path))
print(f"{len(gone)} redirect to a page that no longer exists, written as 410 Gone:")
for path in gone:
    print("  " + " -> ".join(path) + " (not a live page)")

apache = [f"RedirectMatch 301 ^{old}$ {SITE}{new}" for old, new in final.items()]
apache += [f"RedirectMatch 410 ^{path[0]}$" for path in gone]
nginx = [f"location = {old} {{ return 301 {SITE}{new}; }}" for old, new in final.items()]
nginx += [f"location = {path[0]} {{ return 410; }}" for path in gone]
open("redirects.conf", "w", encoding="utf-8").write("\n".join(apache) + "\n")
open("redirects-nginx.conf", "w", encoding="utf-8").write("\n".join(nginx) + "\n")
print(f"\nredirects.conf, {len(apache)} Apache rules; the first two and the last:")
print("\n".join("  " + line for line in apache[:2] + apache[-1:]))
print(f"redirects-nginx.conf, {len(nginx)} Nginx locations; the first two and the last:")
print("\n".join("  " + line for line in nginx[:2] + nginx[-1:]))

Output

24 redirects read, 20 live pages
2 chains, each now one hop:
  /menu/mango-cake -> /cakes/mango-cake -> /cakes/mango-mousse
  /menu/choco-truffle -> /cakes/choco-truffle -> /cakes/eggless-truffle
1 loop, left out until someone decides where it should go:
  /offers -> /offers/diwali -> /offers
1 redirect to a page that no longer exists, written as 410 Gone:
  /menu/plum-cake -> /cakes/plum-cake (not a live page)

redirects.conf, 22 Apache rules; the first two and the last:
  RedirectMatch 301 ^/menu/mango-cake$ https://punebakes.example/cakes/mango-mousse
  RedirectMatch 301 ^/menu/choco-truffle$ https://punebakes.example/cakes/eggless-truffle
  RedirectMatch 410 ^/menu/plum-cake$
redirects-nginx.conf, 22 Nginx locations; the first two and the last:
  location = /menu/mango-cake { return 301 https://punebakes.example/cakes/mango-mousse; }
  location = /menu/choco-truffle { return 301 https://punebakes.example/cakes/eggless-truffle; }
  location = /menu/plum-cake { return 410; }

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 redirect_map.py

It found what grows in every real map: 2 chains, now each one hop; 1 loop between /offers and /offers/diwali, which a person must settle, since only someone at the bakery knows where offers should go; and 1 redirect to the plum cake, which no longer exists, now a 410. Two choices in its rules are deliberate. Apache’s Redirect matches the start of a path, so Redirect 301 /menu/ /cakes/ would also catch every address below /menu/; RedirectMatch with ^ and $ matches one address exactly (mod_alias), as Nginx’s location = does (ngx_http_rewrite_module). And the targets are full https addresses, so the same rules placed on the http host send old links there in one hop. Apache also uses the first rule that matches, so these exact rules go before any rule that sends all of http to https. This session writes the rules and lets Apache check them:

apache-test.conf: a minimal configuration that loads the rules CONF · redirects/apache-test.conf
# A minimal Apache httpd configuration whose one job is to load the rules redirect_map.py wrote, so that
# httpd -t can check them. The module paths are those of macOS; on Linux they are usually under
# /usr/lib/apache2/modules/. On a real server the same lines go in the site's VirtualHost, or in .htaccess.
ServerName punebakes.example
LoadModule mpm_prefork_module /usr/libexec/apache2/mod_mpm_prefork.so
LoadModule unixd_module /usr/libexec/apache2/mod_unixd.so
LoadModule authz_core_module /usr/libexec/apache2/mod_authz_core.so
LoadModule alias_module /usr/libexec/apache2/mod_alias.so
DocumentRoot "."
ErrorLog /dev/stderr

Include redirects.conf
Apache httpd checks the 22 rules Python · redirects/session.py
"""Writes the bakery's redirect rules and checks them with Apache httpd, the way a terminal shows it.

Each command is printed after "$ ", then what it printed: standard output and standard error together. python3 runs
redirect_map.py, which writes redirects.conf; httpd -t then reads apache-test.conf, which includes it, and reports
whether every rule is valid. httpd -t starts no server and opens no port. To replay the session, type its commands in
a terminal on a computer with Python 3 and Apache httpd 2.4 installed.
"""

import shlex
import subprocess
import sys

COMMANDS = [
    "python3 redirect_map.py > summary.txt",
    "grep -c RedirectMatch redirects.conf",
    "httpd -v | head -n 1",
    'httpd -t -d "$PWD" -f apache-test.conf',
]

failed = 0
for command in COMMANDS:
    print(f"$ {command}")
    run = command.replace("python3 ", f"{shlex.quote(sys.executable)} ", 1)  # the pinned Python of this run
    done = subprocess.run(run, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True,
                          env={"PATH": "/usr/sbin:/usr/bin:/bin"})
    print(done.stdout, end="")
    failed += done.returncode != 0
sys.exit(1 if failed else 0)

Output

$ python3 redirect_map.py > summary.txt
$ grep -c RedirectMatch redirects.conf
22
$ httpd -v | head -n 1
Server version: Apache/2.4.67 (Unix)
$ httpd -t -d "$PWD" -f apache-test.conf
Syntax OK

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 session.py

Apache 2.4.67 accepts all 22. The Nginx file is checked the same way with nginx -t on a server that runs Nginx.

Bring the plum cake back

Press Edit, add "/cakes/plum-cake", to LIVE and run again: no redirect points at a missing page any more, and the old plum cake address becomes the 22nd 301.

Redirect Checker Follow one of your own old addresses hop by hop, with the status, the Location and the time of every redirect.

Checkpoint

Check: Chains and loops

  1. Question 1 of 2 How many redirect hops do Google's crawlers follow by default?

    Type a number.

    A hint

    The bakery's old link needed 3, well within it.

    Show the answer: Question 1 of 2

    Answer: 10 hops

    Up to 10 hops by default; Google's site-move guide still asks for one hop, or at most a few, because every hop costs visitors another request.

  2. Question 2 of 2 /offers redirects to /offers/diwali, and /offers/diwali back to /offers. What does Search Console's Page indexing report show for them?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Redirect error, whose causes include a redirect loop

    The program left the loop out of the rules until someone at the bakery decides where offers should go.

Pages that are gone answer 404 or 410, never 200

A page that no longer exists should say so in its status. 404 Not Found says that the server has no current page at the address, without saying whether for now or for good; 410 Gone says that the page is no longer available and that this “is likely to be permanent” (RFC 9110, sections 15.5.5 and 15.5.11). For Google the two work alike: an address that answers any 4xx but 429 is taken out of the index over time, and a 404 is “a strong signal not to crawl that URL again” (crawl budget). Search Console lists such addresses as Not found (404), and Google notes that a 404 is not necessarily a problem when a page was removed without a replacement; the ones to fix are those the site still links to or lists in its sitemap, and moved content gets a 301 instead (Page indexing report).

The trouble starts when the status and the page disagree. A page that answers 200 while it shows a “not found” message, or very little, is what Google calls a soft 404, and such pages “will continue to be crawled, and waste your budget”. Two more cases count the same way: old addresses sent in bulk to one unrelated page, such as the home page, which “might be treated as a soft 404 error” (How to move a site), and a filter that finds nothing, for which Google asks for a 404 (faceted navigation). The program below checks six of the bakery’s answers for exactly that disagreement:

Does each status say what its page says? Python · soft404/check_answers.py
"""Does each answer's status code say what its page says? Six of Pune Bakes' addresses, checked one by one.

Each row is what the bakery's server sends: the status, the Location of a redirect, and the start of the page's main
text. A page that tells the visitor something is missing while its status says 200 is what Google calls a soft 404,
and a removed product redirected to the home page may be treated as one.
"""

ANSWERS = [  # address, status, Location (redirects only), the start of the main text
    ("/cakes/blueberry-cheesecake", 200, None, "Blueberry cheesecake, baked on a biscuit base"),
    ("/cakes/plum-cake", 404, None, "We couldn't find that cake. Here are this week's bakes"),
    ("/cakes/strawberry-tart", 410, None, "The strawberry tart is no longer made"),
    ("/cakes/black-forest-mini", 200, None, "Sorry, this cake is no longer available"),
    ("/cakes/?flavour=durian", 200, None, "No cakes match these filters"),
    ("/cakes/vanilla-sponge", 301, "/", None),
]
SAYS_MISSING = ("no longer available", "couldn't find", "no cakes match", "not found")


def verdict(address, status, location, text):
    missing = text is not None and any(p in text.lower() for p in SAYS_MISSING)
    if status == 200 and missing:
        return "soft 404: the page says missing, the status says 200"
    if status in (301, 308) and location == "/":
        return "home page for a removed product: may count as a soft 404"
    if status in (404, 410):
        return f"{status}: the page is gone and the status says so"
    return f"{status}: the status matches the page"


for address, status, location, text in ANSWERS:
    print(f"{address}\n  {verdict(address, status, location, text)}")

Output

/cakes/blueberry-cheesecake
  200: the status matches the page
/cakes/plum-cake
  404: the page is gone and the status says so
/cakes/strawberry-tart
  410: the page is gone and the status says so
/cakes/black-forest-mini
  soft 404: the page says missing, the status says 200
/cakes/?flavour=durian
  soft 404: the page says missing, the status says 200
/cakes/vanilla-sponge
  home page for a removed product: may count as a soft 404

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 check_answers.py

Three answers are right, three are not. The black forest mini page and the durian filter both tell the visitor that nothing is there while their status says 200, and the vanilla sponge, which the bakery stopped making, sends its visitors to the home page. Each needs the status that matches its page: 404 or 410 for the two missing pages, and for the sponge either a 301 to a close replacement, such as another sponge cake, or a 410.

A friendly not-found page that answers 200

A template that shows “Sorry, this cake is no longer available” with status 200 tells visitors the truth and Google the opposite. Keep the friendly page, with links to this week’s bakes, and send it with status 404 or 410: the message still reaches people, and the status reaches Google.

Checkpoint

Check: Pages that are gone, and soft 404s

  1. Question 1 of 2 Which of these answers is a soft 404?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Status 200 and the text "Sorry, this cake is no longer available"

    A soft 404 is a disagreement between the status and the page; the check found three of them among six answers.

  2. Question 2 of 2 A shop stops selling 300 products and redirects all of them to its home page. What is the risk, and the better choice?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Google may treat them as soft 404s; redirect each to a close replacement, or answer 404 or 410

    A redirect should lead to the closest equivalent; where none exists, the honest answer is that the page is gone.

A short pause answers 503, and robots.txt keeps answering 200

Sometimes a site must stop for a few hours: a new database, a payment provider’s outage, a sale that overloads the server. Google’s first advice is to keep the site online with less in it, for example by turning off the cart, which leaves search visibility unchanged; a whole site switched off should be a matter of “a few days at most” (Temporarily pause or disable a website). For a pause of a day or two Google suggests an informational error page with status 503 and a Retry-After: An HTTP response header, such as Retry-After: 3600, that tells a client how many seconds to wait, or until which date and time, before trying again. It goes with 503 and 429 answers. header, either a date or a number of seconds, as in Retry-After: 3600 (RFC 9110, section 10.2.3). And it gives one warning in plain words: never answer 503 for robots.txt itself, because that “blocks all crawling”.

For a longer closure Google suggests a stand-in page that answers 200; what it advises against is a 403, 404 or 410 or a noindex, each of which removes the site’s addresses from Search, and a robots.txt block of the whole site, which may remove them too. A server that is only overloaded by one client may answer 429 Too Many Requests instead, which RFC 6585 defines for rate limiting, and which Google’s crawlers treat like a 5xx: they slow down. Here is the bakery’s maintenance switch for Apache, which answers 503 for everything except robots.txt and the maintenance page itself:

maintenance.conf: 503 and Retry-After, robots.txt left alone CONF · maintenance/maintenance.conf
# Pune Bakes' maintenance switch for Apache httpd 2.4: while it is in the configuration, every address
# answers 503 Service Unavailable with Retry-After: 3600 (try again in an hour), except robots.txt and the
# maintenance page itself, which keep answering 200. Remove the block when the work is done.
# The module paths are those of macOS; on Linux they are usually under /usr/lib/apache2/modules/.
ServerName punebakes.example
LoadModule mpm_prefork_module /usr/libexec/apache2/mod_mpm_prefork.so
LoadModule unixd_module /usr/libexec/apache2/mod_unixd.so
LoadModule authz_core_module /usr/libexec/apache2/mod_authz_core.so
LoadModule rewrite_module /usr/libexec/apache2/mod_rewrite.so
LoadModule headers_module /usr/libexec/apache2/mod_headers.so
DocumentRoot "."
ErrorLog /dev/stderr

RewriteEngine On
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteCond %{REQUEST_URI} !=/maintenance.html
RewriteRule ^ - [R=503,L]
ErrorDocument 503 /maintenance.html
Header always set Retry-After "3600" "expr=%{REQUEST_STATUS} == 503"
Apache httpd checks the maintenance switch Python · maintenance/session.py
"""Checks the bakery's maintenance configuration with Apache httpd, the way a terminal shows it.

Each command is printed after "$ ", then what it printed: standard output and standard error together. httpd -t reads
the configuration and reports whether its syntax is valid; it starts no server and opens no port. To replay the
session, type its commands in a terminal on a computer with Apache httpd 2.4 installed.
"""

import subprocess
import sys

COMMANDS = [
    "httpd -v | head -n 1",
    'httpd -t -d "$PWD" -f maintenance.conf',
]

failed = 0
for command in COMMANDS:
    print(f"$ {command}")
    done = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True,
                          env={"PATH": "/usr/sbin:/usr/bin:/bin"})
    print(done.stdout, end="")
    failed += done.returncode != 0
sys.exit(1 if failed else 0)

Output

$ httpd -v | head -n 1
Server version: Apache/2.4.67 (Unix)
$ httpd -t -d "$PWD" -f maintenance.conf
Syntax OK

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 session.py

[R=503] works because a RewriteRule may return any valid status, and with one outside the 300s it serves no target and stops (RewriteRule flags); Header always with expr= adds Retry-After only to the 503 answers, error documents included (mod_headers). The check proves that Apache accepts the configuration; once it is live, Google’s guide suggests checking the answers with a tool such as curl, curl -I and the address, before the work starts. Step through the pause from Googlebot’s side:

Interactive · message by message A two-hour pause, done safely Step through the bakery's maintenance window from the crawler's side, and the one mistake that would block all crawling.
A two-hour pause, done safely, step 5 of 5. Messages so far: Googlebot to The bakery's server: GET /robots.txt; Googlebot to The bakery's server: GET /cakes/mango-mousse; Googlebot to The bakery's server: GET /cakes/mango-mousse.GooglebotThe bakery's servermaintenance onGET /robots.txtGET /cakes/mango-mousseGET /cakes/mango-mousse200 again

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. The switch is on. The bakery moves its shop to a new database. For two hours every address answers 503 with Retry-After 3600, except robots.txt and the maintenance page.
  2. robots.txt stays readable. Googlebot fetches robots.txt first and gets 200 with the usual rules, so crawling is allowed as before.
  3. A page answers 503. The mango mousse page answers 503 and Retry-After 3600, try again in an hour. Google reads a 5xx as temporary, keeps the indexed page for now and slows its crawling of the site.
  4. The mistake to avoid. Had robots.txt answered 503 as well, Google would have stopped crawling the whole site. Google's guide says plainly not to return 503 for robots.txt.
  5. Back to 200. The work ends inside the two hours. Every address answers 200 again, and Google raises its crawl rate step by step. A 503 suits a day or two at most; a longer closure keeps a page that answers 200.

Every code of this lesson answers one question: what happened to the content at this address? Answer it, and two more, for an address on your own site:

Interactive · answer and compare Which status does this address need? Answer three questions about one address that is changing. The table marks the codes that fit and says why the others do not.
What happened to the content at this address?
Is the change for good?
Do forms send POST requests to this address?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Seven status codes against a permanent move, a temporary move, a form that posts to the address and a page that is gone
Status code A permanent move A temporary move Forms post to it The page is gone
301 Moved Permanently Says: moved for good Good Google shows the target and treats it as canonical Poor it says the move is for good Mixed browsers may turn a POST into a GET Poor it says the page lives on elsewhere
308 Permanent Redirect Says: moved for good, same method Good Google treats it like a 301 Poor it says the move is for good Good the request method must not change Poor it says the page lives on elsewhere
302 Found Says: moved for now Poor a weak signal: the old address usually stays in results Good the source stays in results while the move lasts Mixed browsers may turn a POST into a GET Poor it says the page lives on elsewhere
307 Temporary Redirect Says: moved for now, same method Poor Google treats it like a 302 Good the source stays in results while the move lasts Good the request method must not change Poor it says the page lives on elsewhere
404 Not Found Says: nothing here Poor it says nothing moved Poor Google starts removing the address Mixed there is nothing to send the form to Good Google removes the address from its index over time
410 Gone Says: gone, and for good Poor it says nothing moved Poor it says the page is gone for good Mixed there is nothing to send the form to Good gone for good; Google handles it like a 404
503 Service Unavailable Says: busy or paused, come back Poor it says the page will be back Mixed a pause of a day or two, with Retry-After, not a move Mixed the form fails until the service is back Poor it says the page will be back
How the answers decide
  • “What happened to the content at this address?” It moved to another address: rules out 404 Not Found, 410 Gone and 503 Service Unavailable. The content lives at another address, so send people and crawlers there with a redirect.
  • “What happened to the content at this address?” It is gone, with no close replacement: rules out 301 Moved Permanently, 308 Permanent Redirect, 302 Found, 307 Temporary Redirect and 503 Service Unavailable. Nothing replaces the page, and old addresses sent to an unrelated page such as the home page may be treated as soft 404s; answer 404 or 410.
  • “What happened to the content at this address?” It is paused for a day or two: rules out 301 Moved Permanently, 308 Permanent Redirect, 302 Found, 307 Temporary Redirect, 404 Not Found and 410 Gone. The page is coming back soon. A 503 with Retry-After says so, while a 404 or 410 would start removing it from the index.
  • “What happened to the content at this address?” It moved to another address and “Is the change for good?” Yes, for good: rules out 302 Found and 307 Temporary Redirect. A permanent move gets a permanent redirect, so that Google shows the new address and treats it as canonical.
  • “What happened to the content at this address?” It moved to another address and “Is the change for good?” No, for a while: rules out 301 Moved Permanently and 308 Permanent Redirect. A temporary move should keep the old address in results; a permanent redirect would replace it.
  • “What happened to the content at this address?” It moved to another address and “Do forms send POST requests to this address?” Yes, forms post to it: adds a caveat to 301 Moved Permanently and 302 Found. When browsers follow a 301 or a 302 they may turn a POST into a GET and lose the form's data; 308 and 307 keep the method.
  • “What happened to the content at this address?” It is gone, with no close replacement and “Is the change for good?” Yes, for good: adds a caveat to 404 Not Found. Both remove the address for Google, which treats every 4xx but 429 alike; 410 also tells everyone else that the page is gone for good.

In short: 301, or 308 when forms post to it, for a move that stays; 302 or 307 for a move that ends; 404 or 410 for a page that is gone; and 503 with Retry-After for a pause of a day or two.

Checkpoint

Check: A short pause with 503

  1. Question 1 of 2 During a maintenance window, what should robots.txt answer?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 200 with its usual rules

    The bakery's maintenance switch answers 503 for everything except robots.txt and the maintenance page.

  2. Question 2 of 2 A shop closes for three weeks. What should its pages answer?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 200, with the site online and the cart turned off, or a stand-in page that answers 200

    The longer a site is off, the more a 5xx costs; a working site with less in it costs nothing.

Practise: clean up 40 legacy redirects

Spice Box moved twice, and its server still holds the redirects of both moves. Write clean() so that each of the 40 old addresses reaches its live page in one hop or answers 410, and give the status code for six special cases; the sample tests follow every address hop by hop:

Exercise · Medium · Python

Clean up 40 legacy redirects

Spice Box moved twice: the first shop's /shop/*.html pages became /products/*, and those became /spices/* and /blends/*. RULES in redirect_plan.py holds every redirect the server has today, LIVE the addresses that answer 200, and LEGACY the 40 old addresses that links and bookmarks still use.

  1. Write clean(rules, live, legacy) so that it returns, for every legacy address, either (301, target) with the live address its redirects finally reach, so that every old address arrives in one hop, or (410, None) when its redirects end on an address that is not live or go round in a loop.
  2. Fill in SPECIAL with the status code each of the six cases needs, as the lesson describes them.

The sample tests follow every legacy address, check that each 301 lands on a live page, that the chains are collapsed and that the dead ends and the loop answer 410, and then check the six status codes.

Starter code · redirect_plan.py

"""Spice Box's redirects after two moves: /shop/*.html became /products/*, then /products/* became /spices/*."""

RULES = {  # every redirect the server has today: old address -> where it points
    "/shop/kashmiri-chilli.html": "/products/kashmiri-chilli",
    "/shop/black-pepper.html": "/products/black-pepper",
    "/shop/cardamom.html": "/products/cardamom",
    "/shop/turmeric.html": "/products/turmeric",
    "/shop/cinnamon.html": "/products/cinnamon",
    "/shop/cloves.html": "/products/cloves",
    "/shop/saffron.html": "/products/saffron",
    "/shop/cumin.html": "/products/cumin",
    "/shop/coriander.html": "/products/coriander",
    "/shop/fenugreek.html": "/products/fenugreek",
    "/shop/mustard-seeds.html": "/products/mustard-seeds",
    "/shop/nutmeg.html": "/products/nutmeg",
    "/shop/star-anise.html": "/products/star-anise",
    "/shop/bay-leaves.html": "/products/bay-leaves",
    "/shop/fennel.html": "/products/fennel",
    "/shop/ajwain.html": "/products/ajwain",
    "/products/kashmiri-chilli": "/spices/kashmiri-chilli",
    "/products/black-pepper": "/spices/black-pepper",
    "/products/cardamom": "/spices/cardamom",
    "/products/turmeric": "/spices/turmeric",
    "/products/cinnamon": "/spices/cinnamon",
    "/products/cloves": "/spices/cloves",
    "/products/saffron": "/spices/saffron",
    "/products/cumin": "/spices/cumin",
    "/products/coriander": "/spices/coriander",
    "/products/fenugreek": "/spices/fenugreek",
    "/products/mustard-seeds": "/spices/mustard-seeds",
    "/products/nutmeg": "/spices/nutmeg",
    "/products/star-anise": "/spices/star-anise",
    "/products/bay-leaves": "/spices/bay-leaves",
    "/products/fennel": "/spices/fennel",
    "/products/ajwain": "/spices/ajwain",
    "/shop/index.html": "/products/",
    "/products/": "/spices/",
    "/shop/garam-masala-blend.html": "/products/garam-masala",
    "/products/garam-masala": "/blends/garam-masala",
    "/products/chai-masala": "/blends/chai-masala",
    "/shop/long-pepper.html": "/products/long-pepper",
    "/products/holi-box": "/offers/holi-box",
    "/offers/holi-box": "/products/holi-box",
}
LIVE = {  # the addresses that answer 200
    "/spices/kashmiri-chilli", "/spices/black-pepper", "/spices/cardamom",
    "/spices/turmeric", "/spices/cinnamon", "/spices/cloves",
    "/spices/saffron", "/spices/cumin", "/spices/coriander",
    "/spices/fenugreek", "/spices/mustard-seeds", "/spices/nutmeg",
    "/spices/star-anise", "/spices/bay-leaves", "/spices/fennel",
    "/spices/ajwain", "/spices/", "/blends/garam-masala",
    "/blends/chai-masala",
}
LEGACY = [  # 40 old addresses that links, bookmarks and other sites still use
    "/shop/kashmiri-chilli.html", "/shop/black-pepper.html", "/shop/cardamom.html",
    "/shop/turmeric.html", "/shop/cinnamon.html", "/shop/cloves.html",
    "/shop/saffron.html", "/shop/cumin.html", "/shop/coriander.html",
    "/shop/fenugreek.html", "/shop/mustard-seeds.html", "/shop/nutmeg.html",
    "/shop/star-anise.html", "/shop/bay-leaves.html", "/shop/fennel.html",
    "/shop/ajwain.html", "/products/kashmiri-chilli", "/products/black-pepper",
    "/products/cardamom", "/products/turmeric", "/products/cinnamon",
    "/products/cloves", "/products/saffron", "/products/cumin",
    "/products/coriander", "/products/fenugreek", "/products/mustard-seeds",
    "/products/nutmeg", "/products/star-anise", "/products/bay-leaves",
    "/products/fennel", "/products/ajwain", "/shop/index.html",
    "/shop/garam-masala-blend.html", "/products/garam-masala", "/products/chai-masala",
    "/shop/long-pepper.html", "/products/long-pepper", "/products/holi-box",
    "/offers/holi-box",
]


def clean(rules, live, legacy):
    """Return {old address: (status, target)} for every legacy address: (301, a live address) or (410, None)."""
    return {old: (301, rules[old]) for old in legacy if old in rules}


# The status code each case needs: one number per case.
SPECIAL = {
    "checkout": None,  # the checkout is down for one hour of maintenance
    "discontinued": None,  # a spice blend that will not come back, with no replacement
    "form-moved": None,  # the order form moved for good, and other sites' forms still POST to the old address
    "festival-offer": None,  # /offers/ points to /offers/holi/ for the seven days of the festival
    "too-many-requests": None,  # a crawler sends 50 requests a second to the search page
    "http-home": None,  # the http:// address of the home page, now on https
}
The sample tests · test_redirect_plan.py
from redirect_plan import LEGACY, LIVE, RULES, SPECIAL, clean


def plan():
    return clean(RULES, LIVE, LEGACY)


def test_every_legacy_address_planned():
    """plans all 40 legacy addresses, each as a 301 or a 410"""
    result = plan()
    assert set(result) == set(LEGACY)
    assert {status for status, _ in result.values()} <= {301, 410}


def test_redirects_end_on_live_pages_in_one_hop():
    """every 301 goes straight to an address that answers 200, so no redirect leads to another"""
    for old, (status, target) in plan().items():
        if status == 301:
            assert target in LIVE, f"{old} goes to {target}, which is not a live page"


def test_chains_collapsed():
    """the old shop's pages skip /products/ and go straight to /spices/ and /blends/"""
    result = plan()
    assert result["/shop/cardamom.html"] == (301, "/spices/cardamom")
    assert result["/shop/garam-masala-blend.html"] == (301, "/blends/garam-masala")
    assert result["/shop/index.html"] == (301, "/spices/")


def test_dead_ends_and_loops_answer_410():
    """long pepper is gone and the Holi box's two addresses point at each other: all four answer 410"""
    result = plan()
    for old in ["/shop/long-pepper.html", "/products/long-pepper", "/products/holi-box", "/offers/holi-box"]:
        assert result[old] == (410, None), old


def test_special_cases():
    """the status codes of the six special cases"""
    assert SPECIAL["checkout"] == 503
    assert SPECIAL["discontinued"] in (404, 410)
    assert SPECIAL["form-moved"] == 308
    assert SPECIAL["festival-offer"] in (302, 307)
    assert SPECIAL["too-many-requests"] == 429
    assert SPECIAL["http-home"] in (301, 308)
A hint

Follow the rules from each legacy address one step at a time, keeping a set of the addresses already visited. Stop when the address has no rule, or when the next one is already in the set: that is a loop. Then one question decides the answer: did you stop on a live address, and not in a loop?

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Then practise the five ideas of this lesson, starting where your answers have been weakest:

Practice that adapts to you

Practise this lesson

15 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 15 What do Google's crawlers take every 4xx code except 429 to mean?

    Choose one answer.

    Show the answer: Question 1 of 15

    Answer: The content does not exist

    404, 410, 401, 403 and the rest all mean, to Google, that there is no content to index.

  2. Question 2 of 15 A server answers some of Googlebot's requests with 429 Too Many Requests. What do Google's crawlers do?

    Choose one answer.

    Show the answer: Question 2 of 15

    Answer: They treat it as overload, like a 5xx, and slow their crawling for a while

    RFC 6585 defines 429 for rate limiting, and Google's crawlers respond by slowing down.

  3. Question 3 of 15 To slow Googlebot down, an administrator makes the server answer it with 403. Does that work?

    Choose one answer.

    Show the answer: Question 3 of 15

    Answer: No; 4xx codes other than 429 do not change the crawl rate, and the pages are treated as missing

    For real overload a short spell of 503 or 429 is the signal Google reads; a 403 drops the pages instead.

  4. Question 4 of 15 How does Google treat a meta refresh with a delay of 0 seconds?

    Choose one answer.

    Show the answer: Question 4 of 15

    Answer: As a permanent redirect

    Where a server-side redirect is impossible, an instant meta refresh is the next most reliable way to move a page.

  5. Question 5 of 15 A site moves from http to https for good. Which redirect should every http address get?

    Choose one answer.

    Show the answer: Question 5 of 15

    Answer: A 301, or a 308, to the same path on https

    The first lesson of this module set this up for the bakery: every http and www address answers with one 301.

  6. Question 6 of 15 A shop's platform allows neither server redirects nor meta refresh tags, only JavaScript. What should it know about a JavaScript redirect?

    Choose one answer.

    Show the answer: Question 6 of 15

    Answer: Google sees it only if it renders the page successfully, so it ranks below server-side and meta refresh redirects

    Ask the platform for server-side redirects first, then a meta refresh; Google ranks JavaScript below both, and only a link with a note below it.

  7. Question 7 of 15 Googlebot follows up to 10 hops. Why point old addresses straight at the final page anyway?

    Choose one answer.

    Show the answer: Question 7 of 15

    Answer: Every hop costs visitors and crawlers another request, and Google advises against chains

    The cleaned map sent the bakery's two chains to their final pages in one hop each.

  8. Question 8 of 15 A map holds the rules A to B, B to C and C to D, and D answers 200. How many redirects does a visit to A pass through before it reaches the page?

    Type a number.

    A hint

    Count the arrows from A to D.

    Show the answer: Question 8 of 15

    Answer: 3 redirects

    A to B, B to C and C to D: three redirects, and four requests in all. After the cleanup, A, B and C each go straight to D in one.

  9. Question 9 of 15 These two lines are in this order in an Apache configuration. Where does a request for /menu/mango-cake go?

    Read the code, then choose one answer.

    Redirect 301 /menu/ https://punebakes.example/cakes/
    Redirect 301 /menu/mango-cake https://punebakes.example/cakes/mango-mousse
    Show the answer: Question 9 of 15

    Answer: To /cakes/mango-cake, through the first rule; the second is never reached

    Put specific rules first, or use RedirectMatch with ^ and $, as the program does, so that each rule matches one address exactly.

  10. Question 10 of 15 How does Google treat 410 Gone compared with 404 Not Found?

    Choose one answer.

    Show the answer: Question 10 of 15

    Answer: Alike, as content that does not exist; 410 adds, for everyone, that the page is gone for good

    Use 410 when you know the page will not come back, and 404 otherwise; Google removes both in time.

  11. Question 11 of 15 Search Console lists 120 addresses as Not found (404). Which of them need work?

    Choose one answer.

    Show the answer: Question 11 of 15

    Answer: Those the site still links to or lists in its sitemap, and any whose content moved, which get a 301

    Fix the site's own links first, redirect what moved, and leave the rest answering 404.

  12. Question 12 of 15 The filter /cakes/?flavour=durian finds no cakes and shows "No cakes match these filters" with status 200. What should it answer?

    Choose one answer.

    Show the answer: Question 12 of 15

    Answer: 404, under the same address

    The check flagged the durian filter as a soft 404 for the same reason: the page says there is nothing, the status says success.

  13. Question 13 of 15 Which values can a Retry-After header hold?

    Choose one answer.

    Show the answer: Question 13 of 15

    Answer: A number of seconds, such as 3600, or an HTTP date

    The bakery's switch sends Retry-After: 3600, an hour, with every 503.

  14. Question 14 of 15 The bakery cannot take orders for two days, but its pages are fine. What does Google suggest first?

    Choose one answer.

    Show the answer: Question 14 of 15

    Answer: Keep the site online, turn off the cart and show a notice

    Switch off only what must stop; Google's guide also suggests keeping the notice out of snippets with data-nosnippet.

  15. Question 15 of 15 To pause its site for a month, a shop adds noindex to every page. What happens?

    Choose one answer.

    Show the answer: Question 15 of 15

    Answer: The pages leave Search as they are recrawled, and coming back can be slow

    For a month, keep the site up with less in it, or keep a stand-in page that answers 200.

Interview questions

Warm-up (fresher to 2–5 years): how does Google treat a 301 redirect differently from a 302?

Both send visitors and Googlebot to another address, and Google follows both. The difference is what Google shows: a 301, like a 308, is permanent, so Google takes it as a strong signal that the target should be canonical and shows the target in results; a 302, like a 307, is temporary, a weak signal, so Google usually keeps showing the source address. Use a 301 when a page has moved for good, after a rename or a move to HTTPS, and a 302 when it will come back, such as an offer page pointing to this week’s sale. If forms post to the address, use 308 or 307, because browsers may turn a POST into a GET when they follow a 301 or a 302. Whichever you use, point old addresses straight at the final page, not through a chain.

Two more questions follow, about a migration that redirected every old product to the home page and a week of maintenance. Make the first decision of each before you open it:

Checkpoint

Your first decision

  1. Question 1 of 2 Interview brief: after a redesign, a shop redirected all 1,200 old product addresses to its home page, and its search clicks fell. What do you do first?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Map each old product to its closest new page, or to 404 or 410, and replace the mass redirect

    A site move works address by address: each old address goes to its equivalent, in one hop.

  2. Question 2 of 2 Interview brief: a team plans a week of maintenance and wants every address, robots.txt included, to answer 503 all week. What do you say first?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Never 503 for robots.txt, and a week is too long for 503; keep the site up with less in it

    Start with what can stay online; switch off only what must stop, and keep robots.txt answering 200.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    After a redesign, a shop redirected all 1,200 old product addresses to its new home page, and its search clicks fell by 30 %. What went wrong, and how do you repair it?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A booking site plans a week of maintenance and proposes answering 503 for every address, robots.txt included, for the whole week. What do you advise instead?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A status code tells Google what happened before it reads the page: 2xx goes on to indexing, 3xx is followed, 4xx but 429 means the content is missing, and 429 or 5xx slows crawling.
  • A permanent redirect, 301 or 308, makes Google show the target; a temporary one, 302 or 307, keeps the source; 308 and 307 keep a form’s POST a POST.
  • Every old address should reach its final page in one hop: clean chains and loops from the redirect map and write exact rules with full targets.
  • A page that is gone answers 404 or 410; a “not found” page with status 200, an empty filter and old pages sent in bulk to the home page are soft 404s.
  • A pause of a day or two answers 503 with Retry-After, robots.txt keeps answering 200, and a longer closure keeps a page that answers 200.

Terms in this lesson

meta refresh
An HTML meta element with http-equiv="refresh" that sends the browser to another address after a delay. Google treats a delay of 0 seconds as a permanent redirect and a longer one as temporary.
permanent redirect
A redirect with status 301 or 308, or an instant meta refresh, that says the content has moved for good. Google treats the target as canonical and shows it in results.
redirect chain
Two or more redirects in a row, A to B to C. Google's crawlers follow up to 10 hops, but every hop costs visitors a request, so old addresses should point straight at the final page.
redirect loop
Redirects that lead back to an address already passed, A to B to A, so no page is ever reached. Browsers stop with an error, and Search Console reports a redirect error.
Retry-After
An HTTP response header, such as Retry-After: 3600, that tells a client how many seconds to wait, or until which date and time, before trying again. It goes with 503 and 429 answers.
soft 404
A page that says something is missing, or holds almost nothing, while its status code says 200. Search Console reports it as a soft 404; a missing page should answer 404 or 410.
status code
The three-digit number at the start of every HTTP response that says what happened: 2xx success, 3xx a redirect, 4xx a client error such as 404, 5xx a server error. Google's crawlers act on it before they read the page.
temporary redirect
A redirect with status 302, 303 or 307, or a delayed meta refresh, that says the move will be undone. Google follows it but usually keeps showing the source address in results.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.