Skip to main content

Confirm

Are you sure?

Accessibility & HTML · Checked once per domain

Custom 404 error pageWhat it checks and how to fix it

What it checks

Requests a URL that cannot exist on the site and inspects the answer. It passes when the server responds with a 404 status and a real page (a title or substantial content, not the bare nginx or Apache default); it warns when the error page is a generic server page, or when the missing URL does not answer 404 at all (a soft 404).

Why it matters

Visitors land on missing pages through old links, typos and moved content. A branded 404 with navigation and search keeps them on the site, while a bare server page sends them back to the search results. Answering missing URLs with 200 instead of 404 also lets search engines index junk URLs as duplicate content.

How to fix it

Serve a branded page for missing URLs, and keep the 404 status code.

<!-- 404.html -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>Page not found</title></head>
<body>
  <header><!-- site navigation --></header>
  <main>
    <h1>Page not found</h1>
    <p>The page you are looking for does not exist or has moved.</p>
    <a href="/">Back to the homepage</a>
  </main>
</body>
</html>

nginx:

error_page 404 /404.html;
error_page 500 502 503 504 /500.html;
location = /404.html { internal; }

Apache (.htaccess):

ErrorDocument 404 /404.html
ErrorDocument 500 /500.html

Rails: edit public/404.html and public/500.html, or render your own templates by setting config.exceptions_app = routes and routing /404 to a controller that renders with status: :not_found.

Cloudflare Pages serves a top-level 404.html automatically. For single-page apps, make sure the catch-all route returns status 404 for unknown paths instead of 200.

Monitor this automatically

Full Stack Audit runs this check and 126 others on your site on a schedule, and emails you when one that passed starts failing.

More Accessibility & HTML checks