The short version
- A good 404 page does four things: it says plainly that the page does not exist, offers one clear way home, gives a search box, and keeps the site's normal navigation.
- A 404 page must be served with a real 404 HTTP status; a not found page that returns 200 is a soft 404, which Google reports as an error and may keep in its index.
- Redirecting every missing address to the homepage is also treated as a soft 404, so only redirect pages that have a true replacement.
- Motion on a 404 page should be slow and ambient, and it must stop for visitors who set prefers-reduced-motion.
- Putting the 404 page on the same brand ground as the homepage makes a dead end feel like part of the product instead of a server error.
On this page
Good 404 page design comes down to four jobs: say what happened in one plain line, give one obvious way home, offer a search, and keep your normal navigation so the visitor is still on your site. Then make sure the server answers with a real 404 status, and put the page on the same brand ground as everything else, so a dead end still looks like you.
The number does the explaining, the line underneath does the comforting.
Or lead with the words and keep 404 as a small label. Both work if the ground is yours.
What a 404 page must do
Someone arrived from an old link, a typo or a search result that went stale. They wanted something. Your page has seconds to get them to it, or to something close. Everything on the page should serve that, in this order.
- 1
Say what happened
One short line: the page is not here. Do not blame the visitor ("you typed it wrong") and do not show a server stack trace. A large
404is fine as a label; the sentence is what people read. - 2
Give one way home
A single primary button back to the homepage, or to the most useful hub for your product (docs, dashboard, shop). One button, not five equal ones.
- 3
Offer a search
A search box catches the visitor who knows what they wanted. Point it at your existing site search; if you have none, a few links to your most visited pages do the same job.
- 4
Keep the nav
Use the site's normal header and footer. A bare page with no navigation feels like the site broke; the usual header tells people they are still somewhere safe.
Avoid
- A blank server page in a default font
- Copy that blames the visitor
- Five equal buttons and no clear next step
- Hiding the header and footer
- Redirecting every miss to the homepage without a word
- A joke so long the link home falls below the fold
Do
- Your brand ground, type and logo
- One calm line that says the page is not here
- One primary button home, one search box
- The same header and footer as every page
- A real 404 status, and redirects only for pages that moved
- Everything important visible on a phone without scrolling
Return a real 404 status (soft 404s hurt SEO)
The design is what people see; the HTTP 404 status is what search engines read. If your not found page answers with 200 OK, Google calls it a soft 404: a page that says it is missing while the server says it is fine. Search Console lists these as errors, and the crawler wastes visits on addresses that should be dropped.
Two common causes. Single page apps that render "not found" in the browser after the server already sent 200. And catch-all redirects that send every missing address to the homepage, which Google also treats as a soft 404. Redirect with a 301 only when a page truly moved to a new address; everything else should get the 404 page with a 404 status.
error_page 404 / 404.html;Status it sends
ErrorDocument 404 / 404.html (a local path, not a full URL)Status it sends
Where the 404 page lives
app/ not-found.tsx, or call notFound()Status it sends
Where the 404 page lives
404.html file at the site rootStatus it sends
Where the 404 page lives
Status it sends
ErrorDocument a full https address.curl -sI https://example.com/this-page-does-not-exist | head -n 1
# Want: HTTP/2 404
# Soft 404: HTTP/2 200Tone: calm, short and a little human
A 404 is a small failure, so the copy should be small too. One line of personality is plenty; the job is getting people back on track. Write it the way your product already talks, in the same voice as your brand, and keep the button label literal: "Back to home" beats a clever pun on the one word people need to understand instantly.
404 copy ideas you can adapt
- Plain: "This page doesn't exist. Let's get you home."
- Calm: "Nothing lives here yet."
- Owning it: "We moved things around and this link didn't keep up."
- Product voice: "This route returned nothing. Unlike our API."
- Helpful: "Looking for the docs? They're one click away."
- Short: "Wrong turn."
- Map: "You've reached the edge of the map."
- Honest: "This page is gone. The rest of the site is right where you left it."
- For shops: "That product isn't here any more. Here's what is."
- For a waitlist: "Not built yet. Want to know when it is?"
Gentle motion, with prefers-reduced-motion
A slow drift in the background makes a 404 feel alive instead of broken. Keep it ambient: a long, slow loop that never pulls the eye from the button, the kind of seamless loop you would put behind a hero. Animating background-position over 20 seconds or more is cheap and calm; the animated CSS gradient guide covers the technique in depth.
Some people set their device to reduce motion because movement makes them unwell. Honour the prefers-reduced-motion media query and stop the animation entirely for them; the page should look finished standing still. Our reduced motion guide explains what to keep and what to cut.
Put the 404 on your brand ground
The fastest way to make a dead end feel like your product is to reuse the ground from your homepage hero. Same colours, same type, same logo: the visitor knows instantly they are in the right place. Set the words where the background is calmest and check contrast, as in text on a gradient.
If your brand wears a Mark on Gradiently, you can see a 404 page set on it in Explore, next to app icons, headers and docs heroes, or try it on your brand to see the same ground across every surface before you build.
Copyable 404 page: HTML and CSS
Here is a complete, single file 404 page: brand header, one line, one button home, a search box, a slow gradient drift and a full stop for reduced motion. Swap in your name, links and colours, then serve it with a 404 status.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title>Page not found · Outpost</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
grid-template-rows: auto 1fr;
font-family: system-ui, sans-serif;
color: #fff7f5;
background:
radial-gradient(45% 55% at 15% 15%, #e2412a 0%, transparent 70%),
radial-gradient(45% 55% at 85% 85%, #c2185b 0%, transparent 70%),
linear-gradient(160deg, #3b0a12 0%, #7a1020 55%, #1a0508 100%);
background-size: 160% 160%, 160% 160%, 100% 100%;
animation: drift 24s ease-in-out infinite alternate;
}
@keyframes drift {
from { background-position: 0% 0%, 100% 100%, 0 0; }
to { background-position: 40% 30%, 60% 70%, 0 0; }
}
@media (prefers-reduced-motion: reduce) {
body { animation: none; }
}
header {
display: flex;
align-items: center;
gap: 24px;
padding: 24px clamp(20px, 5vw, 56px);
}
header a { color: inherit; text-decoration: none; }
header .logo { font-weight: 700; margin-right: auto; }
main {
display: grid;
place-content: center;
justify-items: center;
gap: 20px;
padding: 24px;
text-align: center;
}
.code { font-size: 14px; letter-spacing: 0.2em; opacity: 0.8; }
h1 { margin: 0; font-size: clamp(2rem, 6vw, 4rem); line-height: 1.05; }
.home {
padding: 14px 24px;
border-radius: 999px;
background: #fff7f5;
color: #3b0a12;
font-weight: 600;
text-decoration: none;
}
form { display: flex; gap: 8px; width: min(420px, 100%); }
input {
flex: 1;
padding: 12px 16px;
border: 1px solid rgb(255 247 245 / 0.4);
border-radius: 999px;
background: rgb(26 5 8 / 0.35);
color: inherit;
font: inherit;
}
</style>
</head>
<body>
<header>
<a class="logo" href="/">Outpost</a>
<a href="/docs">Docs</a>
<a href="/pricing">Pricing</a>
<a href="/blog">Blog</a>
</header>
<main>
<p class="code">404</p>
<h1>Nothing lives here yet.</h1>
<a class="home" href="/">Back to home</a>
<form action="/search" method="get" role="search">
<input type="search" name="q" placeholder="Search the site" aria-label="Search the site">
</form>
</main>
</body>
</html>noindex keeps it out of results even if a host misconfigures the status.The same thinking applies to every small page founders skip: if you are building a pre-launch page next, the waitlist page design guide uses the same ground and the same one line, one action rule.
Questions people ask
What should a 404 page include?
A plain line saying the page does not exist, one clear button home, a search box or a few popular links, and the site's normal header and footer. Keep it on your brand's colours and type so visitors know they are still on your site.
What is a soft 404?
A soft 404 is a page that tells visitors it is missing while the server returns a 200 OK status. Google reports these in Search Console and they waste crawling on pages that should be dropped, so serve not found pages with a real 404 status.
Should I redirect 404 pages to the homepage?
Not as a blanket rule. Google treats mass redirects to the homepage as soft 404s, and visitors lose the context of what they were looking for. Use a 301 redirect only when a page moved to a specific new address.
Can a 404 page be animated?
Yes, as long as the motion is slow and ambient and never distracts from the button home. Stop the animation for visitors who set prefers-reduced-motion.
How do I check my 404 page returns the right status?
Run curl -sI on an address that does not exist and read the first line: it should say 404. Browser developer tools show the same status in the Network panel.
Written by Gradiently
The team behind Gradiently, a design tool built around Marks: living gradients that make everything you design look like yours.
See our profile