Developer docs

Integration

When a visitor hits a 404 you ask no404, get the best matching URL back and send them there. There are three ways to do it — and the difference is not what the visitor sees, it's the HTTP status the search engine sees.

Which path should I pick?

All three get the visitor to the right page. The difference is the HTTP status your server returns, and that difference decides the SEO outcome: an address that returns 301 carries its accumulated value to the new one, an address that stays 404 does not.

PathHTTP statusWho it's for
WordPress plugin301WordPress sites. No code, installed from the admin panel.
Server-side301Anyone writing their own code. We hand you a ready specification.
Browser snippetstays 404No server access, or you just want to try it in five minutes.
The snippet is the easiest path, but the one thing it cannot do is change the HTTP status: the page moves for the visitor and stays dead for the search engine. If you have server access, pick one of the first two.

WordPress pluginPublished on WordPress.org

Catches the 404 on the server, asks no404 and returns a real 301. It doesn't touch your theme files and requires no code.

  • WordPress 6.0+ · PHP 7.4+
  • Caches results locally — protecting your quota and the rate limit.
  • If no404 doesn't answer, the page falls back to its normal 404 (fail-open); the plugin never keeps your site waiting.

Installation

  1. In your WordPress admin, go to Plugins → Add New and search for no404.
  2. Click Install Now and activate it.
  3. Paste the API key from your dashboard into the plugin settings.
The plugin is published in the official WordPress directory and is open source (source code). Install it from the directory: the .zip can be uploaded by hand, but that install gets no automatic updates — when a security patch ships, your site stays on the old version.

Server-side integration

If you write your own code, you can ask no404 wherever you produce a 404 and return a real 301. You don't have to design this from scratch: the dashboard generates a ready integration specification for your site.

The specification is not a snippet, it's an engineering document: timeouts, mandatory caching, a blocklist, the 301/302 rule, plus loop and open-redirect protection. Hand the file to your developer, or straight to an AI coding agent.

Download it from the dashboard → site detail → Integration tab. The specification is generated from your site's address and settings; we don't keep a copy here — a document kept in two places eventually becomes two documents.

Caching is not optional

In a server-to-server call all of your traffic counts as coming from a single IP, and the rate limit (120 requests per minute) applies to that IP. If you don't cache responses locally, a busy site will hit the limit and redirects will stop silently. The specification includes this as a mandatory item.

The minimal version (Node.js)

const res = await fetch(
  "https://www.no404.tr/api/v1/resolve/YOUR_API_KEY?path=" + encodeURIComponent(path),
  { headers: { Origin: "https://yoursite.com" } }
);
const data = await res.json();

// REDIRECT or a high-scoring CATALOG match → permanent (301); everything else → temporary (302).
if (data.redirect) {
  const permanent = data.source === "REDIRECT" || data.score >= 0.5;
  // örn. Express: res.redirect(permanent ? 301 : 302, data.redirect);
}

Browser snippet

This path leaves the HTTP status at 404

The redirect happens in JavaScript, so the server still returned a 404. The visitor reaches the right page, but the search engine keeps treating the old address as dead and no link value is passed on. If you can reach your server, pick one of the two paths above.

Add the code below to your site's 404 page. Replace YOUR_API_KEY with the API key from your dashboard.

<!-- no404: add this to your 404 page -->
<script>
(function () {
  var p = location.pathname + location.search;
  var ref = document.referrer;
  fetch("https://www.no404.tr/api/v1/resolve/YOUR_API_KEY?path=" + encodeURIComponent(p) + "&ref=" + encodeURIComponent(ref))
    .then(function (r) { return r.json(); })
    .then(function (d) { if (d && d.redirect) location.replace(d.redirect); })
    .catch(function () {});
})();
</script>

Next.js (App Router)

Inside app/not-found.tsx:

"use client";
import { useEffect } from "react";

export default function NotFound() {
  useEffect(() => {
    const p = location.pathname + location.search;
    fetch(`https://www.no404.tr/api/v1/resolve/YOUR_API_KEY?path=${encodeURIComponent(p)}&ref=${encodeURIComponent(document.referrer)}`)
      .then((r) => r.json())
      .then((d) => { if (d.redirect) location.replace(d.redirect); })
      .catch(() => {});
  }, []);
  return <p>Page not found, redirecting you…</p>;
}
You manage your API key and allowed origins from dashboard → site detail.

Endpoint reference

A single endpoint used by all three paths; it accepts both GET and POST.

GETPOST/api/v1/resolve/{apiKey}

Parameters

apiKeypathYour site's API key (required).
pathquery / bodyThe path that returned 404, e.g. /missing-page (required).
refquery / bodyWhere the visitor came from (document.referrer). Optional; empty = direct visit.

GET example

curl "https://www.no404.tr/api/v1/resolve/YOUR_API_KEY?path=/14g-gold-ring-102" \
  -H "Origin: https://yoursite.com"

POST example

curl -X POST "https://www.no404.tr/api/v1/resolve/YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Origin: https://yoursite.com" \
  -d '{"path":"/14g-gold-ring-102"}'

Response & status codes

A successful response returns JSON:

{
  "success": true,
  "found": true,
  "redirect": "https://yoursite.com/14g-gold-ring",
  "score": 0.92,
  "source": "CATALOG"
}

Response fields

foundbooleanWhether a confident match was found (can be false on a fallback redirect).
redirectstring | nullThe full URL to redirect to. If set, send the visitor there (fallbacks included).
scorenumberMatch score between 0 and 1 (1 = a manual redirect).
sourceenumREDIRECT (manual) · CATALOG (automatic) · FALLBACK (below threshold, fallback address) · NONE (no match).

Status codes

200Success (found may be true or false).
403Origin not allowed, or tracking is paused.
404Invalid API key.
422Invalid or missing 'path'.
429Rate limit exceeded (too many requests).

Origin lock & security

Your API key is protected by an origin lock. Requests are only accepted from the allowed origins you define in the dashboard. Even if your key leaks, a browser request from another domain is rejected with 403 and no CORS response is returned.

  • When you add your site, your domain is added as an allowed origin automatically (with and without www).
  • You can add further domains from the dashboard.
  • If a key leaks, regenerate it from the dashboard; the old key becomes invalid immediately.
In a server-to-server call the browser sends no Origin header, so the origin lock never engages; protection comes from the key plus the rate limit. Keep the key on your server and never embed it in the client.

Best practices

  • Prefer the server side: it's the only path that produces a 301; the snippet carries no SEO value.
  • Cache the responses: in a server-side integration this is not optional — all traffic counts as one IP.
  • Connect your sitemap: match quality depends on how current your catalog is.
  • Review the threshold: if you don't want overly aggressive redirects, raise it (0.3 recommended).
  • Define manual redirects for critical paths; they override automatic matching.
  • Rate limit: 120 requests per minute per key + IP.

Ready?

Add your site, grab your key, and be live within minutes.

Start free