# Custom 404 page

- **Pattern:** `ab-002548` (`site-health-check.trust-polish.custom-404`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002548
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002548)

## Why it matters

The default framework 404 page — Next.js's plain "404 | This page could not be found," nginx's white error screen, or a bare "Cannot GET /path" — breaks the site's visual identity at the worst possible moment: when a user has just hit a dead link and is deciding whether to leave. A custom 404 with navigation recovers the session; a default 404 bounces the user. It also signals an unfinished build to anyone who stumbles onto it.

## Severity rationale

Medium because default 404s directly increase bounce rate at dead links and erode perceived polish on every broken URL.

## Remediation

Ship a branded 404 page that reuses the site's header, nav, and footer and links back to the homepage and primary destinations. In Next.js App Router, place it at `app/not-found.tsx`; in Pages Router, `pages/404.tsx`; for static hosts, `public/404.html`. Confirm the response code after deployment:

```bash
curl -s -o /dev/null -w '%{http_code}\n' https://yoursite.com/does-not-exist
# expect: 404
```

## Detection

- **ID:** `custom-404`
- **Severity:** `medium`
- **What to look for:** Fetch `{BASE}/nonexistent-page-audit-check-xyz` and capture both the HTTP status code and the response body (first 50 KB). Check the status code (should be 404, not 200). Examine the body for indicators of a custom page: count the number of navigation links (`<a>` tags), check for the site's own CSS (stylesheets or inline styles beyond defaults), look for branded content. Compare against known default 404 patterns: "Cannot GET", "Not Found" (bare text), Next.js default "404 | This page could not be found", nginx default HTML, Apache default HTML.
- **Pass criteria:** The 404 response returns HTTP status 404 and the body contains a custom-branded page with at least 2 of: navigation links back to the site, the site's own styling/CSS, branded content or messaging. The page must not match known default framework or server 404 templates.
- **Fail criteria:** The 404 page is a raw server error, framework default template, or generic web server page with no custom branding.
- **Skip (N/A) when:** The main site itself returns an error (4xx/5xx) — if the homepage is down, testing the 404 page is not meaningful.
- **Detail on fail:** `"404 page is the default Next.js error page — no custom branding"` or `"Server returns plain 'Not Found' text"`
- **Remediation:** A custom 404 page keeps users on your site when they hit a dead link. Create a branded 404 page with navigation:

  ```
  # Next.js App Router
  app/not-found.tsx

  # Next.js Pages Router
  pages/404.tsx

  # Static sites
  public/404.html (or 404.html at root)
  ```

  Include your site header/nav, a friendly message, and a link back to the homepage. Verify with: `curl -s -o /dev/null -w '%{http_code}' {BASE}/nonexistent-page` (should return 404, not 200).

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-002548
