How To Add A Custom 404 Page (And When To Redirect Home)

A custom 404 page keeps visitors moving when a link breaks. Copy the 404.html below, and see the three cases where redirecting home is the better call.
The OxyPages Team · · 13 min read
Someone clicked a link to your site and landed on nothing. Maybe you renamed a file last month. Maybe a newsletter from March still points at a URL that moved. Either way they are staring at a dead end, and the next thing most people do is close the tab.
A custom 404 page is the fix, and it is one file. You publish 404.html at the root of your site, and your host serves it whenever a visitor asks for something that is not there. Instead of a stranger's error screen they get your page, your links, and a way back into the site.
There is a second option people reach for: send every missing URL straight to the homepage. It sounds tidier. It is usually the worse choice, and I want to be specific about the few times it is not.
Three parts, then: the file you can copy, why the status code matters more than the design, and a straight answer on the redirect question.
TL;DR: A custom 404 page is one file, named 404.html, published at the root of your site. It replaces the default error screen for every missing URL, the visitor keeps the address they typed, and the response stays a real 404, which is exactly what a search engine needs to see. Redirecting missing pages to your homepage is the other option, and it is the wrong one almost every time: it hides broken links from you and dumps the visitor somewhere they never asked for. Redirect home only on a one-page site, a campaign page with no subpages, or during a short migration. The copy-paste file is below.
What Visitors See When A Page Is Missing
They see whatever the host serves when no file matches the URL, and by default that screen carries the host's name, not yours. A custom 404 page is how you take it back.
On OxyPages the default is a page headed "Page Not Found" that tells the visitor there is nothing at that address and, if they followed a link, to contact the site owner. It is served with a real 404 status, so nothing is faked. It is just not your page, and it gives the visitor nowhere to go next.
The reason a URL goes missing is almost always dull. A file got renamed. A subdomain changed and the old address was released the moment it was saved. A page was deleted in a tidy-up and something out there still links to it. If a whole site has gone quiet rather than a single page, the website not loading checklist works through those causes in order.
For a single dead URL none of that helps the person already looking at it.
What Is A Custom 404 Page, Exactly?
A custom 404 page is an ordinary HTML file, named 404.html, that your host serves in place of its own error screen whenever a request does not match a real file. There is no plugin, no config file and no build step. It is a page like any other page you have published.
Two things make it different from the rest of your site.
It has to work from any address. A visitor could hit it at /blog/old-post, so a stylesheet loaded as style.css resolves against /blog/ and comes back empty. Use absolute paths that start with a slash, or keep everything inside the one file. The help article on 404 pages makes the same point, and it is the mistake I see most often.
And the response keeps its 404 status. Every page your browser loads comes with a status code: 200 means here it is, 404 means not found, 302 means look over there instead. Serving a friendly apology page with a 200 status tells a crawler the page exists and is fine, so the dead URL stays in the index and competes with your real ones. Google calls that a soft 404, and it is the quiet failure mode of every hand-rolled error page.
A 404.html avoids it for free: the host serves your file and keeps the 404 status.
Copy This 404.html Into Your Site

Here is a custom 404 page you can ship as it stands. It loads no fonts, no scripts and no stylesheets from anywhere else, so it renders instantly and cannot break when something outside your site does. (One exception: free plans get the host's small badge script injected into every page, this one included.)
<!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</title>
<style>
:root {
color-scheme: light dark;
--bg: #f5f6f8;
--card: #ffffff;
--text: #14171c;
--muted: #5c6673;
--line: #e2e5ea;
--accent: #2f6df6;
--on-accent: #ffffff;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0d1015;
--card: #171b22;
--text: #eaeef4;
--muted: #9aa4b2;
--line: #272d37;
--accent: #6c9bff;
--on-accent: #0d1015;
}
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
padding: 24px;
background: var(--bg);
color: var(--text);
font: 16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
}
.card {
width: 100%;
max-width: 560px;
padding: 44px 32px;
background: var(--card);
border: 1px solid var(--line);
border-radius: 18px;
text-align: center;
box-shadow: 0 1px 2px rgba(0, 0, 0, .05), 0 16px 40px rgba(0, 0, 0, .06);
}
.badge {
display: inline-block;
margin: 0 0 18px;
padding: 6px 14px;
border: 1px solid var(--line);
border-radius: 999px;
color: var(--muted);
font-size: 12px;
font-weight: 700;
letter-spacing: .14em;
text-transform: uppercase;
}
h1 {
margin: 0 0 10px;
font-size: clamp(26px, 6vw, 36px);
line-height: 1.2;
letter-spacing: -.02em;
}
.lede { max-width: 44ch; margin: 0 auto 26px; color: var(--muted); }
.search { display: flex; gap: 8px; margin: 0 0 22px; }
.search input {
flex: 1 1 auto;
min-width: 0;
padding: 12px 14px;
background: var(--bg);
color: var(--text);
border: 1px solid var(--line);
border-radius: 10px;
font: inherit;
}
.btn {
display: inline-block;
padding: 12px 20px;
border: 1px solid transparent;
border-radius: 10px;
background: var(--accent);
color: var(--on-accent);
font: inherit;
font-weight: 600;
text-decoration: none;
white-space: nowrap;
cursor: pointer;
}
.btn.ghost {
background: transparent;
color: var(--text);
border-color: var(--line);
}
.links {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px 22px;
margin-top: 26px;
padding-top: 22px;
border-top: 1px solid var(--line);
}
.links a { color: var(--muted); font-size: 15px; text-decoration: none; }
.links a:hover, .links a:focus-visible { color: var(--text); text-decoration: underline; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.sr-only {
position: absolute;
width: 1px; height: 1px;
margin: -1px; padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
border: 0;
}
@media (max-width: 420px) {
.card { padding: 32px 20px; }
.search { flex-direction: column; }
.btn { width: 100%; }
}
</style>
</head>
<body>
<main class="card">
<p class="badge">Error 404</p>
<h1>We can't find that page</h1>
<p class="lede">
The link that brought you here is probably old, or the address has a typo
in it. Nothing is broken on your side.
</p>
<form class="search" id="site-search" role="search"
action="https://www.google.com/search" method="get">
<label class="sr-only" for="q">Search this site</label>
<input id="q" name="q" type="search" placeholder="Search this site"
autocomplete="off" />
<button class="btn ghost" type="submit">Search</button>
</form>
<a class="btn" href="/">Back to the homepage</a>
<!-- Swap these for your real pages. Absolute paths only. -->
<nav class="links" aria-label="Main">
<a href="/">Home</a>
<a href="/about.html">About</a>
<a href="/contact.html">Contact</a>
</nav>
</main>
<script>
document.getElementById('site-search').addEventListener('submit', function (e) {
e.preventDefault();
var term = document.getElementById('q').value.trim();
var query = 'site:' + location.hostname + (term ? ' ' + term : '');
location.href = 'https://www.google.com/search?q=' + encodeURIComponent(query);
});
</script>
</body>
</html>
Four things to change before you publish it:
- The three links in the
navblock, so they match the pages you actually have - The heading and the sentence under it, in your own wording
- The two accent colours,
--accentin the light block and in the dark block, to your brand colour - The
titletag, if you want your site name in the browser tab
The search box needs no editing. It reads the domain from the address bar and, when the visitor presses Search, runs a site search on Google, which is the only way to search a static site with no server behind it. If you would rather not send people to Google, delete the form block and the script at the bottom.
If you would rather fill in a form than edit HTML, the 404 page generator builds the same file.
Should Missing Pages Redirect To Your Homepage Instead?
Usually not, and I will argue that harder than most guides do.
A redirect feels like the polite option next to a custom 404 page. Nobody sees an error, the visitor lands on something that works, and the site looks maintained. Three things go wrong underneath that.
You stop finding out. A 404 in your analytics is a report that a link is broken, complete with the URL and where the click came from. Redirect it away and every broken link on the internet pointing at you looks like homepage traffic. The bug never surfaces.
The visitor loses the thread. They clicked something specific, and dropping them on the homepage makes finding it their problem. A custom 404 page that says "that one moved, here are the sections" respects what they were doing.
And crawlers file it badly. A 302 to the homepage tells a search engine the requested URL temporarily lives at a page that is obviously not it. Google resolves that as a soft 404 anyway, so you get none of the tidiness you wanted and you lose the honest signal you had.
| Default error page | Your own 404.html | Redirect to home | |
|---|---|---|---|
| What the visitor sees | The host's generic error | Your page and your links | Your homepage |
| Address bar | The URL they typed | The URL they typed | Changes to / |
| Status code | 404 | 404 | 302, then 200 |
| What a crawler learns | The page is gone | The page is gone | Little, and often files it as a soft 404 |
| Can they keep browsing | Only by typing | Yes | Yes, from the top |
| Do you learn the link is broken | Only if your host logs it | Yes | Rarely |
| Works on a free plan | Yes | Yes | Paid feature, where it exists |
| Best for | Nothing, it is the fallback | Almost every site | One-page and campaign sites |
When Redirecting Home Is Actually Right
There are three cases, and they are narrower than the feature makes them sound.
- A genuine one-page site. If
/is the only real page, every other URL is a typo or a bot probe. There is no context to preserve, so sending them to the only page you have is not hiding anything. - A campaign or event page with no subpages. Same logic, plus print material and QR codes with slightly wrong URLs on them. A redirect quietly rescues those.
- A short migration window. You have moved URLs, the new structure is live, and you have not written the per-URL mapping yet. A redirect home for a week beats a wall of errors. If your host supports per-URL redirects, a 301 to the actual new address beats both.
Outside those three, build the page. A custom 404 page with real navigation costs you twenty minutes once and keeps paying.
How To Add A Custom 404 Page To A Live Site

Save the file as 404.html at the top level of your site, publish, then visit a URL you know does not exist.
That works anywhere. Netlify, Cloudflare Pages and GitHub Pages all serve a root 404.html the same way, so if you are on one of those already, stay put.
Here is the version for OxyPages, which takes about a minute:
- Open your website in the dashboard and go to the Code Editor.
- Save the code above on your computer as
404.html, lowercase, and make the four edits. - Drag that file onto the editor window. It lands at the root of your site. There is no new-file button, so dragging a file in or asking the editor's AI to write one are the ways in.
- Press Publish. Publishing from the Code Editor keeps your other files, so nothing else changes.
- Open
yoursite.myoxypages.com/nope-not-a-pagein a new tab and check that your custom 404 page appears and the address stays as you typed it.
One warning about the upload route. Upload Files, Upload Folder and Upload ZIP File replace the whole site with what you upload, so include your custom 404 page alongside every other file rather than on its own.
There is also a paid setting called "404 Redirect To Home" on the website's Settings page, which turns missing URLs into a 302 to the homepage. It never overrides your file. If a 404.html is published, it is served, on every plan, and the toggle does not come into play.
To check the status code rather than trust it, open your browser's developer tools, go to the Network tab and reload the missing URL. The first row should read 404. A 200 there means you have the soft 404 problem.
What To Do Next
Publish the file. A custom 404 page is the highest-value twenty minutes on this list, because it works on the traffic you already have instead of chasing more.
Then go looking for what is actually breaking. Click through your last newsletter and open the oldest link you can find to your own site.
If you want the redirect toggle as well, the plan comparison lists it row by row. For most sites the free file is the whole answer, and your Claude HTML file sits in the same folder beside it.
Let AI Do It For You
Paste this into the OxyPages Code Editor AI, or any coding agent working on your site, and it will build a custom 404 page for you.
Add a custom 404 page to this website.
Create a file called 404.html at the root of the site, not inside a folder.
It must be one self-contained HTML file: all CSS inside a single <style> tag
in the head, no external stylesheets, no web fonts, and no scripts loaded
from another domain.
The page needs:
- A heading saying the page could not be found, in plain language, that does
not blame the visitor
- One sentence explaining the link is probably old or the address is mistyped
- A clear primary button linking to "/"
- A short row of links to this site's real main pages, matching the
navigation used everywhere else on the site
- The same colours and spacing as the rest of this site, so it does not look
like a different website. Match its fonts only if it uses system fonts; if
it loads a web font, use system fonts here instead and match the sizes
- A layout that works down to a 360px wide screen, a visible keyboard focus
ring on every link and button, and light and dark versions using
prefers-color-scheme
Every href and src on this page must be an absolute path starting with a
slash, because the file is served from any URL on the site and relative paths
will break.
Do not add a redirect, a meta refresh, or any JavaScript that changes the
address on its own. The page must stay on the URL the visitor typed until
the visitor clicks or submits something themselves. A search box that
navigates on submit is fine.
When it is done, tell me which navigation links you used and why.
Read what it gives you before publishing. Agents are good at this one, and they still occasionally slip a relative path or a Google Font into the head.
FAQ
Do I Need A Paid Plan For A Custom 404 Page?
No. Publishing your own 404.html works on every plan, free ones included, because it is just another file in your site. The paid feature is the "404 Redirect To Home" setting, which is the option you probably do not want anyway.
Will My 404 Page Show Up In Google Search Results?
No, as long as it is served with a 404 status, which is what happens when the host serves your 404.html for a missing URL. Search engines drop URLs that return 404. A custom 404 page only becomes an indexing problem if you build it as an ordinary page and link to it, which is why you should never put /404.html in your navigation.
What Happens If I Have Both A 404.html And The Redirect Setting On?
The file wins, every time and on every plan. The redirect setting only applies when the site has no 404.html, so you can leave the toggle switched on and still get your custom 404 page. If you are seeing the homepage instead, the file is probably named wrong or sitting in a subfolder.
Why Does My 404 Page Look Unstyled On Some URLs?
Relative paths. A file loaded as style.css resolves against the folder in the URL the visitor typed, so it works at /typo and breaks at /blog/typo. Start every path with a slash, or keep the whole thing self-contained the way the file above does, and a custom 404 page will look identical at every depth of your site.