Stop Serving Soft‑404s: How to Retire Expired Job Pages on Firebase Hosting Without Hurting Your SEO
Job listings disappear every day. If a deleted job URL still returns HTTP 200 (a “soft 404”) or redirects to an irrelevant page, Google wastes crawl budget, keeps the ghost URL indexed, and your Search Console fills with warnings. This article walks through the exact configurations—tested on vacatures.today
—to make Google drop those pages quickly without hurting your ranking signals.
1 | Why Soft‑404s Are Silent SEO Killers
Scenario | What Google Sees | Consequence |
---|---|---|
Deleted job still returns 200 with “page not found” text | Soft 404 | URL remains in index, crawl budget wasted, “Soft 404” warnings |
Deleted job 301‑redirects to the homepage | Misleading redirect → Soft 404 | Same as above + link equity is lost |
Deleted job returns 404 or 410 | Clear “gone” signal | Google drops it fast & frees crawl budget |
2 | What Firebase Hosting Can & Can’t Do
Hosting feature | Status codes it can emit |
---|---|
Static file or rewrite | Always 200 OK |
redirect rule | 3 xx only (301, 302, 303, 307, 308) |
Cloud Function / Cloud Run via rewrite → function | Any code (404, 410, 451…) |
3 | Configuration Playbook
A. Pure Static 404 (No Functions Needed)
If you just want real 404s and have no need for a 410, delete any wildcard rewrites. Firebase automatically serves 404.html
with a correct 404 status when no file or rule matches.
{
"hosting": {
"public": "public",
"headers": [ /* your security headers … */ ]
}
}
B. Static 410 Work‑around (Returns 200 + noindex)
This keeps hosting static but relies on X‑Robots‑Tag: noindex
to de‑index URLs. Google obeys, yet the status code is still 200.
{
"hosting": {
"headers": [{
"source": "/jobs/**",
"headers": [{ "key": "X-Robots-Tag", "value": "noindex" }]
}],
"rewrites": [{
"source": "/jobs/**",
"destination": "/410.html"
}]
}
}
C. True 410 with One Cloud Function
The gold‑standard: Google sees an immediate 410 Gone, crawl budget is freed fastest.
firebase.json
{
"hosting": {
"public": "public",
"rewrites": [
{ "source": "/jobs/**", "function": "gone410" }
]
}
}
functions/index.js
const functions = require("firebase-functions");
const path = require("path");
exports.gone410 = functions.https.onRequest((req, res) => {
res.status(410).sendFile(path.resolve(__dirname, "../public/410.html"));
});
4 | Crafting the Perfect Gone Page
- Return
404
or410
status, not 200. - Add
<meta name="robots" content="noindex">
. - Explain the job is closed and link to current vacancies.
- Keep it lightweight; Googlebot skips heavy JS on error pages.
5 | House‑keeping Checklist
- Remove expired URLs from your XML sitemap immediately.
- Scrub internal links (search results, related‑jobs widgets).
- Use Search Console’s Removals tool only for urgent/legal takedowns; 404/410 is enough for routine expiry.
6 | Conversation Log & Examples
The questions that sparked this guide, with answers in‑line:
User Q 1: “Now we will configure Firebase for 401 if pages are removed.”
A: 401 means “login required”, not “gone”. Use 404 or 410.
User Q 2: “No, I mean 410.”
A: Perfect—410 is the ideal signal for permanently removed content.
User Q 3 (config excerpt):
{ "rewrites": [{ "source": "**", "destination": "/404.html" }] }
A: That returns 200 OK (soft‑404). Delete the rewrite or use a Cloud Function.
User Q 4: “Is it possible to do it without a function?”
A: Firebase Hosting can’t emit non‑200/non‑3xx codes without a backend. Best static fallback is 200 + noindex
.
User Q 5: “Maybe redirect to home or search?”
A: Google treats irrelevant redirects as soft‑404. You lose link equity and create a poor UX.
User Q 6: “404 now good solution for all jobs?”
A: Yes. A true 404 frees crawl budget and removes the page; 410 is faster but optional.
User Q 7 (minimal test):
/vacatures/analytical‑sales‑support.html returns 200 → live.
/jobs/accountant‑boekhouder… returns 404 → gone.
A: Perfect behaviour: live pages stay indexed, expired pages vanish.
7 | Copy‑Paste Mini Configs
7.1 Pure Static 404 (most sites)
{
"hosting": {
"public": "public"
}
}
7.2 Static 410 Work‑around
{
"hosting": {
"headers": [{
"source": "/jobs/**",
"headers": [{"key":"X-Robots-Tag","value":"noindex"}]
}],
"rewrites": [{ "source": "/jobs/**", "destination": "/410.html" }]
}
}
7.3 True 410 with Function
// firebase.json
{
"hosting": {
"rewrites": [
{"source":"/jobs/**","function":"gone410"}
]
}
}
// functions/index.js
exports.gone410 = (req, res) => {
res.status(410).send("This job has been permanently removed.");
};
Take‑away: If there’s no direct replacement for an expired job posting, serve a real 404 (or 410) and let Google clean its index. Anything else—soft‑404, irrelevant redirect, or blanket 200—costs crawl budget and confuses both users and search engines.
Comments
Post a Comment