# 404 page design: a dead end that still looks like you

[Canonical HTML page](https://gradiently.design/guide/404-page-design)

Every site has a page nobody meant to visit. Make it the one that still feels like your product, sends people somewhere useful and tells search engines the truth.

## 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.

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.

A 1920 by 1080 404 page with a large 404 and a short line on a red gradient ground

The number does the explaining, the line underneath does the comforting.

A 1920 by 1080 not found page with the headline Nothing lives here yet on a gradient ground

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 `404` is 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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404) 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.

| Setup | Where the 404 page lives | Status it sends |
| --- | --- | --- |
| Nginx | `error_page 404 /404.html;` | 404 |
| Apache | `ErrorDocument 404 /404.html` (a local path, not a full URL) | 404 |
| Next.js App Router | `app/not-found.tsx`, or call `notFound()` | 404 |
| Static hosts such as GitHub Pages and Netlify | A `404.html` file at the site root | 404 |
| Single page app with client routing | Needs the server or framework to send 404 for unknown routes | Often 200: check it |

Where a custom 404 page usually goes. Apache sends a redirect instead of a 404 if you give `ErrorDocument` a full https address.

```bash
curl -sI https://example.com/this-page-does-not-exist | head -n 1
# Want: HTTP/2 404
# Soft 404: HTTP/2 200
```

Check the status in one line. Run it after every deploy that touches routing.

## Tone: 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](https://gradiently.design/guide/brand-consistency), 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?"

> **Read it on a phone** Many 404 visits come from links shared in chat apps. Check that the line, the button and the search box all fit in the first screen at 390 pixels wide.

## 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](https://gradiently.design/guide/seamless-loop-video) you would put behind a hero. Animating `background-position` over 20 seconds or more is cheap and calm; the [animated CSS gradient](https://gradiently.design/guide/css-animated-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](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) media query and stop the animation entirely for them; the page should look finished standing still. Our [reduced motion](https://gradiently.design/guide/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](https://gradiently.design/guide/hero-section-design). 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](https://gradiently.design/guide/text-on-gradient).

- Ember dark: `linear-gradient(160deg, #3b0a12 0%, #7a1020 55%, #1a0508 100%)`
- Signal red: `radial-gradient(circle at 25% 25%, #e2412a 0%, #8f1530 45%, #2a0610 100%)`
- Crimson to magenta: `linear-gradient(135deg, #1a0508 0%, #6b0f2a 50%, #c2185b 100%)`
- Late sunset: `radial-gradient(circle at 70% 80%, #ff8a65 0%, #d84315 40%, #3e0a0a 100%)`

Red and ember grounds for a 404. Keep the lightest area away from the headline and button so white text stays readable.

If your brand wears a Mark on Gradiently, you can see a 404 page set on it in [Explore](/explore), next to app icons, headers and docs heroes, or [try it on your brand](/try) 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.

```html
<!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>
```

A full 404 page in one file. The drift stops for anyone who prefers reduced motion; `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](https://gradiently.design/guide/waitlist-page-design) guide uses the same ground and the same one line, one action rule.

## FAQ

### 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.
