Guide Remix SEO
How Remix's meta(), loader(), headers(), and liens() route exports contrôler SEO — plus ce que modifié as Remix v2 became React Router, now on v8.
Langues
TL;DR — Remix is a React framework que renders votre pages on le serveur by par défaut — so le contenu is déjà in the HTML avant Google ever loads it. Que goes a long façon toward solving the biggest JavaScript SEO problem, though it doesn’t guarantee indexation or rankings by itself. Vous encore have to définir votre titles, descriptions, and balise canonicals yourself, en utilisant Remix’s per-route
meta()function. SSR is the foundation, pas the whole house. Remarque: Remix v2 merged into React Router (now v8) — Remix 3 (beta) is a separate, newer product; ce page covers the Remix v2 / React Router route API la plupart sites run today.
Ce que Remix is
Remix routes peut render on le serveur and provide document metadata via route APIs. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Remix: Route meta Server-rendered HTML improves initial content delivery but ne fait pas guarantee Search indexation. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics
Remix is a meta-framework construit on React. Plain React builds votre whole page in le navigateur with JavaScript — Google obtient a nearly vide HTML fichier and has to run votre code to voir anything. Remix flips que: it runs votre React components on le serveur and sends back finished HTML with the text, liens, and meta tags déjà in it. Server rendering is the framework par défaut — a project peut aussi be configuré to statically prerender routes or run in SPA mode, so confirmer qui mode a donné site en réalité uses plutôt que assuming from the framework nom alone.
Pour le SEO, that’s a huge head commencer on the par défaut SSR chemin. There’s aucun waiting pour JavaScript, aucun “render queue,” and robots d’exploration que don’t run JavaScript at tout (nombreux AI bots, social preview bots) encore obtenir votre complet content.
Un naming remarque que trips personnes up, and it’s plus layered que it utilisé to be:
in late 2024 the Remix team merged Remix v2’s application APIs into React
Router v7 — même route exports (meta, loader, headers, links,
ErrorBoundary), renamed package. React Router has since déplacé to v8 (June
2026), with v7 encore receiving security updates. Separately, the Remix nom now
aussi refers to Remix 3, a newer beta full-stack framework the team describes
as “a different direction” from React Router — a distinct product, pas simplement a
renamed un. Everything on ce page documents the Remix v2 / React Router v7-v8
route API que la plupart production Remix sites run today; it ne fait pas cover Remix 3.
How vous ajouter SEO tags in Remix
Remix donne chaque route (chaque page) special functions vous export from the fichier:
meta()— sets votre<title>, meta description, Ouvrir Graph tags, and même données structurées. Ce is the principal SEO outil.loader()— récupère données on le serveur (comme a blog post from votre database) avant the HTML is sent. Votremeta()peut utiliser que données, so titles peut be dynamic.links()— adds<link>tags comme favicons and stylesheets.headers()— sets HTTP réponse headers (mise en cache, robots rules).
Here’s the simplest version of a title and description:
export const meta = () => {
return [
{ title: "About Us | My Site" },
{ name: "description", content: "Learn about our team and mission." },
];
};Que renders straight into le serveur HTML — exactly où Google veut it.
The un mistake to éviter
The la plupart courant Remix SEO bug: child pages quietly lose the meta tags définir by
parent layouts. Remix seulement garde the deepest route’s meta() and throws away
the rest unless vous tell it pas to. Si votre homepage layout sets a site-wide
description and votre À propos de page exports its propre meta() sans merging, the
description disappears on que page. The fix is in the Avancé tab.
The simple takeaway
- Remix is a safe SEO choice parce que it’s server-rendered by par défaut.
- Vous encore have to écrire votre titles, descriptions, and canonicals with
meta(). - Watch out pour child pages dropping parent meta tags.
Vouloir the réel version — loader and réel 404s, headers() pour X-Robots-Tag,
balise canonicals two façons, and the React Router v7 migration? Switch to the
Avancé tab. Pour the framework-agnostic background, voir
JavaScript SEO and the
JavaScript frameworks hub.
TL;DR — Remix is SSR-by-default, so content ships in the initial HTML with aucun render-queue dependency — the architecture removes la plupart JS-SEO risk quand SSR is what’s en réalité deployed, though it doesn’t by itself guarantee indexation, ranking, or Core Web Vitals outcomes. The fonctionner is in the per-route exports:
meta()(titles, descriptions, OG, JSON-LD, and dynamic canonicals viatagName: "link"),loader()(server données + réel HTTP 404s/redirections),headers()(Cache-Control,X-Robots-Tag), andlinks()(static canonicals, preloads). The signature gotcha: nested routes drop parent meta unless vous merge it via thematchesargument. Naming, dated: Remix v2’s APIs merged into React Router v7 in 2024; React Router is now on v8 (v7 encore security-supported); Remix 3 (beta) is a separate, newer full-stack framework, pas simply React Router renamed. Ce page covers the Remix v2 / React Router v7-v8 route API.
SSR by par défaut — pourquoi Remix starts ahead
Remix’s server rendering is a framework capability whose deployment behavior dépend on the adapter and route code. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Remix: Route meta Validate the delivered HTML and resources plutôt que assuming a framework par défaut ensures SEO outcomes. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics
Scope remarque: the walkthrough ci-dessous documents the meta() / loader() /
headers() / links() / ErrorBoundary route module API as it exists in Remix
v2 and React Router v7-v8 framework mode — ce que the grand majority of production
Remix/React Router sites run. Remix 3 (beta) is a separate, ground-up rewrite
with différent APIs and isn’t covered ici; vérifier qui un you’re en réalité on
avant copying anything ci-dessous.
Bare React (CRA, Vite + React) ships an vide <div id="root"></div> and builds
lune page in le navigateur. Google peut render que, but you’ve signed up pour the
render queue, statelessness, and DOM-parity problems covered in
JavaScript SEO. Remix doesn’t have que par défaut:
it executes votre nested route tree (Root → Layout → Route) on le serveur and, by
par défaut, sends content-complete HTML on every document requête. Framework mode
peut aussi be configuré to statically prerender routes at construire temps or run as a
client-rendered SPA — so pour quelconque donné deployment, confirmer the réel rendering
mode (via curl/View Source, ci-dessous) plutôt que assuming SSR from the framework
nom.
Google’s propre guidance lines up with ce. From the JavaScript SEO basics doc:
“Server-side or pre-rendering is encore a great idea parce que it rend votre website
faster pour utilisateurs and robots d’exploration, and pas tout bots peut run JavaScript.” Que dernier
clause is the whole argument pour Remix — Bingbot renders JS slowly and incompletely,
and nombreux AI robots d’exploration and social preview bots (Twitterbot, facebookexternalhit)
don’t render at tout. Remix’s SSR output sert tout of les correctement sans special
handling.
Après the initial charger, Remix uses client-side routing pour subsequent navigations
(comme every React framework). That’s fine: Google discovers liens from the SSR’d
HTML and crawls chaque URL as its propre server requête — chaque returning complet HTML. It
doesn’t rely on watching client-side route transitions. And parce que Remix’s <Link>
renders a réel <a href>, liens are crawlable by construction — Google
“peut seulement découvrir votre liens si ils are <a> HTML elements with an href
attribute.”
The meta() export: titles, descriptions, OG, JSON-LD
Every route peut export a meta function returning an array of descriptor objects.
Parce que it peut lire loader données, metadata is dynamic and définir in the initial HTML
<head> — aucun JS-injection delay:
// app/routes/blog.$slug.tsx
import type { MetaFunction } from "@remix-run/node";
export const meta: MetaFunction<typeof loader> = ({ data }) => {
if (!data) return [{ title: "Post Not Found" }];
return [
{ title: `${data.post.title} | My Blog` },
{ name: "description", content: data.post.excerpt },
{ property: "og:title", content: data.post.title },
{ property: "og:image", content: data.post.ogImage },
{ property: "og:type", content: "article" },
{
"script:ld+json": {
"@context": "https://schema.org",
"@type": "Article",
headline: data.post.title,
datePublished: data.post.publishedAt,
author: { "@type": "Person", name: data.post.author },
},
},
];
};The { "script:ld+json": {...} } descriptor renders a proper
<script type="application/ld+json"> tag in the SSR’d <head> — visible to Google’s
parser sans executing quelconque JavaScript. Martin Splitt’s preference s’applique:
“We prise en charge JSON-LD in dynamically rendered content, but it’s généralement meilleur to
have it in the initial HTML.” In Remix, the initial HTML is the par défaut placer it
lands.
Nested routes and meta inheritance — the courant trap
Ce is the Remix SEO mistake. Remix takes the dernier matching route with a meta
export and uses that — parent meta is dropped. A child that exports its own
meta() without merging silently loses every tag the root set (site-wide
description, root OG tags, etc.):
// ❌ Root's description is now gone on this route
export const meta: MetaFunction = () => {
return [{ title: "About Us" }];
};The fix is the matches argument — flatten and spread parent meta:
// ✅ Keep parent meta, append your own
export const meta: MetaFunction = ({ matches }) => {
const parentMeta = matches.flatMap((match) => match.meta ?? []);
return [...parentMeta, { title: "About Us" }];
};
// ✅ Keep parent meta but override only the title
export const meta: MetaFunction = ({ matches }) => {
const parentMeta = matches
.flatMap((match) => match.meta ?? [])
.filter((meta) => !("title" in meta));
return [...parentMeta, { title: "About Us" }];
};Si vous définir global tags, put truly universal ones (charset, viewport) directement in
root.tsx’s JSX où merging jamais strips les, and reserve meta() pour
page-level signals vous en réalité vouloir to override per route.
The loader() function: réel 404s, réel redirections, dynamic meta
Loaders run server-side seulement — DB requêtes, API calls, and secrets jamais reach Googlebot. The SEO payoff is correct Code d’état HTTPs:
// app/routes/products.$id.tsx
import { json, redirect } from "@remix-run/node";
import type { LoaderFunctionArgs } from "@remix-run/node";
export async function loader({ params }: LoaderFunctionArgs) {
const product = await db.products.findById(params.id);
if (!product) {
throw new Response("Product not found", { status: 404 });
// ✅ real HTTP 404 — not a soft 404
}
if (product.movedTo) {
throw redirect(`/products/${product.movedTo}/`, 301); // ✅ real 301
}
return json(product);
}Ce is the antidote to the soft-404 problem SPAs créer — a 200 OK page que
simplement dit “not found.” As John Mueller put it: “Si une page renvoie a 200 but there’s
aucun content — that’s a soft 404. That’s problematic parce que we don’t know to treat it
as a 404. From a exploration standpoint, we’ll simplement garder trying to explorer it.” Remix’s
throw new Response(..., { status: 404 }) propagates a genuine 404, qui lines up
with Google’s instruction to “utiliser a meaningful code d’état, comme a 404 pour une page
que pourrait pas be trouvé.”
Whatever a loader renvoie is exposed to the client même si the component doesn’t render it — treat loaders comme public API endpoints and don’t retourner secrets.
Ce status propagation is ce que se produit on a direct document requête (the cas a robot d’exploration rend). Client-side navigations après hydration are a separate code chemin que peut behave differently, and some hosting adapters rewrite or intercept thrown réponses — vérifier les deux the direct-request and post-hydration behavior on votre réel deployment plutôt que assuming it from the loader code alone.
The headers() function: Cache-Control and X-Robots-Tag
Per-route HTTP headers — the lever pour CDN mise en cache (faster TTFB → meilleur Core Web Vitals) and pour robots directives que fonctionner même on robots d’exploration que don’t lire the HTML corps:
import type { HeadersFunction } from "@remix-run/node";
// CDN-friendly caching
export const headers: HeadersFunction = () => ({
"Cache-Control": "max-age=300, s-maxage=3600, stale-while-revalidate=86400",
});
// HTTP-level noindex — effective for Bingbot and non-rendering crawlers
export const headers: HeadersFunction = () => ({
"X-Robots-Tag": "noindex, nofollow",
});X-Robots-Tag: noindex at the header level reaches robots d’exploration que jamais parse the
corps. By par défaut seulement the deepest route’s headers() runs in a nested tree, so
the simplest pattern is to define headers on leaf routes seulement and éviter merge
complexity.
A meta-noindex caveat worth knowing regardless of framework, from Martin Splitt:
“The noindex tag peut causer Google to skip rendering entirely. So si you’re trying
to noindex via JavaScript, vous may be creating a situation où Google jamais même
runs the JavaScript to voir the noindex.” Remix sidesteps ce parce que the directive
lands in the SSR’d <head> (or an HTTP header), pas in client-only JavaScript.
The links() export and balise canonicals — two façons
links() injects <link> elements (favicons, stylesheet preloads, static
canonicals). But it has aucun accès to loader données — it’s static per route module:
export const links: LinksFunction = () => [
{ rel: "canonical", href: "https://example.com/canonical-url/" },
];Pour dynamic canonicals — paginated, filtered, or parameterized URLs — utiliser meta()
with tagName: "link", qui fait voir data, params, and location:
export const meta: MetaFunction<typeof loader> = ({ data }) => [
{
tagName: "link",
rel: "canonical",
href: `https://example.com/products/${data.product.slug}/`,
},
];The rule: static canonical → links(); dynamic canonical → meta() with
tagName: "link". Ce matches Martin Splitt’s advice to définir canonicals in HTML
plutôt que JavaScript — “définir votre canonical in the HTML, pas with JavaScript… it’s
simplement plus fragile.” Les deux Remix approaches render into le serveur HTML. (Voir the
balise canonical deep dive.)
Error boundaries and 404/5xx pages
Quand a loader, action, or component throws, the route’s ErrorBoundary renders — in
placer, à l’intérieur the surviving layout (nav, footer stay). Paired with a thrown 404
Réponse, vous obtenir a réel 404 status and a usable page:
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
export function ErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error) && error.status === 404) {
return <div><h1>404 — Page Not Found</h1></div>;
}
return <div>Something went wrong.</div>;
}A root-level ErrorBoundary in app/root.tsx catches anything route boundaries
don’t. The myth que “throwing a 404 breaks the layout” is faux — the boundary
renders dans the route hierarchy.
Sitemaps and robots.txt as routes
Remix has aucun built-in sitemap generator; vous construire les as resource routes. The
bracket notation escapes the dot so l’URL is literally /sitemap.xml:
// app/routes/sitemap[.xml].tsx
export async function loader() {
const posts = await db.posts.findMany({ where: { published: true } });
const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${posts.map((p) => ` <url><loc>https://example.com/blog/${p.slug}/</loc><lastmod>${p.updatedAt.toISOString()}</lastmod></url>`).join("\n")}
</urlset>`;
return new Response(body, {
headers: { "Content-Type": "application/xml", "Cache-Control": "public, max-age=3600" },
});
}robots.txt follows the même app/routes/robots[.txt].tsx pattern, returning
text/plain.
Remix, React Router, and the 2026 product split — a dated timeline
Ce has gotten plus layered since the original 2024 merge, so treat it as history plus current state plutôt que a unique fact:
- Dec 2024 — Remix v2 merges into React Router v7.
@remix-run/reactand@remix-run/nodeconsolidate intoreact-router; the@remix-run/*packages encore fonctionner as a bridge. What’s SEO-relevant from ce déplacer:routes.ts— a routing config fichier; routes peut be défini programmatically pour plus flexible Structure d’URLs.- Static pre-rendering — individual routes peut opt into build-time HTML generation (SSG-style), or SPA mode — configuration choices, pas automatic.
- End-to-end type safety —
loaderretourner types flow intometa(), reducing bugs in dynamic meta generation. - Vite — the par défaut bundler since Remix v2; route-level code splitting garde client bundles lean (bon pour TBT/LCP).
- Ce que didn’t modifier: the
meta()/loader()/headers()/links()/ErrorBoundarypattern and the<Meta />/<Links />/<Scripts />components inroot.tsx. Existing Remix v2 SEO code carries over with minimal changements.
- June 2026 — React Router v8 ships. React Router v7 remains security-supported;
Remix v2 and React Router v6 are now end-of-life. The route module SEO API ce
page documents (
meta,loader,headers,links,ErrorBoundary) is the même shape à travers v7 and v8 — vérifier votre installed version’s changelog pour quelconque descriptor-level changements avant copying code verbatim. - Aussi as of 2026 — Remix is ne … plus simplement “the old name for React Router.”
The Remix team describes React Router as leur React meta-framework, and Remix
(now in a “Remix 3” beta) as a separate, newer full-stack framework — “un team,
two projects.” Si you’re auditing or building on
@remix-run/*/react-routerroute exports, ce article’s API guidance s’applique directement. Si you’re on Remix 3, vérifier its documentation independently — the meta/loader/headers/liens pattern décrit ici n’est pas confirmed to carry over unchanged.
Bottom line pour la plupart sites in production today: “Remix SEO” and “React Router SEO” are encore the même route API and the même practical topic. Simplement don’t assume que aussi covers Remix 3.
Vous encore don’t besoin dynamic rendering
Parce que Remix sert HTML on le serveur, vous jamais besoin Rendertron or Prerender.io. Google deprecated dynamic rendering anyway: “Dynamic rendering was a workaround and pas a long-term solution… it creates additional complexities and resource requirements.” SSR is the recommended chemin, and Remix donne it to vous by par défaut.
Auditing a Remix site
- Vérifier the initial HTML with
curlor View Source — pas DevTools Elements (qui montre the post-hydration DOM). - Vérifier réel Code d’état HTTPs on manquant pages (404, pas 200) and redirections (301/302).
- Tester with GSC Inspection d’URL — Remix’s served HTML devrait match the rendered view.
- Regarder pour nested-meta merge bugs — confirmer child pages encore carry the site-wide description and OG tags.
- Validate JSON-LD with the Résultats enrichis Tester, and run a explorer (Ahrefs Site Audit, Screaming Frog) to catch blocked assets and depth problèmes.
None of the ci-dessus is a guarantee of indexation, rankings, or Core Web Vitals — SSR, correct code d’états, and clean metadata supprimer architecture-level risk; the rest encore dépend on content quality, the deployment adapter, and how the page performs contre everything sinon in the SERP.
Pour the base library underneath Remix, voir React SEO; pour the framework-agnostic rendering rules, voir JavaScript SEO and the JavaScript frameworks hub.
AI summary
A condensed prendre on the Avancé version:
- Remix is SSR-by-default — it renders the nested route tree on le serveur and,
by par défaut, ships content-complete HTML on every document requête (framework mode
peut aussi be définir to static prerender or SPA, so vérifier the réel deployed mode).
Aucun render queue, aucun vide root
<div>, and non-rendering robots d’exploration (Bingbot, AI bots, social bots) obtenir complet content — though none of ce guarantees indexation or rankings by itself. meta()is the principal SEO outil — titles, descriptions, OG, JSON-LD ("script:ld+json"), and dynamic canonicals viatagName: "link". It peut lireloaderdonnées, so metadata is content-specific and in the initial HTML.- The signature gotcha: nested routes utiliser the deepest route’s
metaand drop parent meta unless vous merge it with thematchesargument. loader()runs server-side;throw new Response("", { status: 404 })donne a réel 404 (aucun soft 404) andthrow redirect()donne a réel 301/302.headers()setsCache-Control(TTFB/CWV) andX-Robots-Tagat the HTTP level — fonctionne même pour robots d’exploration que don’t lire the corps.links()vsmeta()pour canonicals:links()is static (aucun loader données);meta()withtagName: "link"is dynamic. Static →links(), dynamic →meta().ErrorBoundaryrenders à l’intérieur the surviving layout and pairs with thrown 404s pour correct status + usable page.- Remix v2’s APIs merged into React Router v7 (Dec 2024) — même SEO APIs,
renamed packages (
react-router), nouveauroutes.ts, optional static pre-rendering, Vite bundling. React Router is now on v8 (June 2026; v7 encore security-supported). Separately, Remix 3 (beta) is a newer, distinct full-stack framework — pas simplement React Router sous the old nom. Ce article covers the Remix v2 / React Router v7-v8 route API. Aucun dynamic rendering outils nécessaire pour que API soit façon.
Documentation officielle
Primary-source documentation from Remix / React Router and the moteur de recherches.
Remix / React Router
- Remix —
metafunction — per-route meta tags, descriptors, andmatchesmerging. - Remix —
loaderfunction — server-side données fetching and thrown réponses. - Remix —
headersfunction — per-route HTTP réponse headers. - Remix —
linksfunction —<link>elements (canonical, preload, favicon). - Remix —
ErrorBoundary— route and root error handling. - React Router v7 announcement — the Remix v2 → React Router merge (Dec 2024).
- React Router v8 — the current release (June 2026) and the “one team, two projects” remarque on how Remix 3 now differs from React Router.
- React Router docs — où the Remix v2-lineage route API now lives, currently on v8.
- Comprendre the JavaScript SEO basics — the three-phase explorer/render/index traiter, code d’états,
<a href>liens, and SSR guidance. - Dynamic rendering (deprecated) — pourquoi dynamic rendering is a workaround, pas a solution.
- In-Depth Guide to How Recherche Google Fonctionne — où rendering sits in explorer → index → serve.
Quotes from the source
On-the-record statements from Google que bear directement on Remix’s SSR-first model. Chaque search-engine lien is a deep lien que jumps to the quoted passage.
Google — pourquoi SSR helps
- “Server-side or pre-rendering is still a great idea because it makes your website faster for users and crawlers, and not all bots can run JavaScript.” Jump to quote
- “Google can only discover your links if they are
<a>HTML elements with anhrefattribute.” Jump to quote
Google — code d’états (the loader + ErrorBoundary pattern)
- “To tell Googlebot if a page can’t be crawled or indexed, use a meaningful status code, like a 404 for a page that could not be found or a 401 code for pages behind a login.” Jump to quote
Google — dynamic rendering is deprecated
- “Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” Jump to quote
Remix SEO checklist
A rapide réussir pour quelconque Remix / React Router v7 project:
- Pages importantes are server-rendered (the par défaut) — confirmer content is in
View Source /
curl, pas seulement the post-hydration DOM. - Every indexable route sets a
<title>and meta description via themeta()export. - Child routes que export
meta()merge parent meta via thematchesargument (aucun dropped site-wide tags). - Manquant resources
throw new Response(..., { status: 404 })in theloader— vérifier a réel 404, pas a soft 404 (200 + “not found”). - Déplacé URLs
throw redirect(target, 301)from the loader — réel 301/302. - Balise canonicals are définir in HTML:
links()pour static,meta()withtagName: "link"pour dynamic (paginated/filtered/param URLs). -
noindexis définir in the SSR’d<head>or viaheaders()X-Robots-Tag— jamais client-side seulement. -
headers()sets sensibleCache-Controlpour CDN mise en cache / TTFB on leaf routes. - JSON-LD is ajouté via
{ "script:ld+json": {...} }inmeta()and validated in the Résultats enrichis Tester. -
sitemap.xmlandrobots.txtexist as resource routes (sitemap[.xml].tsx,robots[.txt].tsx) and are submitted in Search Console. - Lien internes utiliser Remix
<Link>(renders réel<a href>). - Aucun
@remix-run/*→react-routerrename surprises si you’re migrating to v7.
The mental models
1. SSR is the floor, pas the ceiling.
Remix renders on le serveur by par défaut, qui removes the discovery/rendering risk
class pour free. It fait pas auto-handle titles, descriptions, canonicals,
données structurées, cache headers, or 404 code d’états — chaque is an explicit meta(),
headers(), links(), or loader decision. SSR is a prerequisite, pas a complet
SEO solution.
2. The correct export pour the correct signal.
- HTML
<head>tags (title, description, OG, JSON-LD, dynamic canonical) →meta() - Static
<link>elements (favicon, preload, static canonical) →links() - Code d’état HTTPs (404, 301, 302) and server données →
loader() - HTTP réponse headers (
Cache-Control,X-Robots-Tag) →headers() - Error/404 page bodies →
ErrorBoundary
3. meta() beats links() quand données matters.
links() can’t voir loader données; meta() peut. So anything que dépend on récupéré
content — a dynamic canonical, a data-driven title — belongs in meta().
4. The nesting par défaut is “deepest wins, parents dropped.”
The decision rule: quelconque child que exports meta() doit consciously choisir to merge
parent meta (matches) or it loses it. Put universal tags (charset/viewport) in
root.tsx JSX où merging can’t strip les.
5. Réel code d’états are an SEO fonctionnalité, pas an accident.
throw new Response(..., { status: 404 }) and throw redirect() are how Remix
avoids the soft-404 / fake-redirect échecs of CSR SPAs. Reach pour thrown Réponses
au lieu de rendering an message d’erreur at a 200.
Remix SEO — cheat sheet
Per-route exports → ce que ils contrôler
| Export | Contrôle | Sees loader données? | SEO utiliser |
|---|---|---|---|
meta() | <head> meta/title/JSON-LD | Yes | Titles, descriptions, OG, JSON-LD, dynamic canonical |
links() | <link> elements | Aucun | Static canonical, favicon, preload |
loader() | Server données + status | n/a (it is the données) | Réel 404/301, server-only fetching |
headers() | HTTP réponse headers | via loaderHeaders | Cache-Control, X-Robots-Tag |
ErrorBoundary | Error/404 page corps | via useRouteError | Usable 404 page in-layout |
Balise canonicals — pick the correct un
| Besoin | Utiliser |
|---|---|
| Static, connu at construire | links() → { rel: "canonical", href } |
| Dynamic (dépend on loader données) | meta() → { tagName: "link", rel: "canonical", href } |
Code d’états from a loader
throw new Response("Not found", { status: 404 }); // real 404
throw redirect("/new-url/", 301); // real 301Fast facts
- Remix is SSR by par défaut — content in the initial HTML, aucun render queue (confirmer the deployed mode; static prerender/SPA are aussi configuration options).
- Nested meta: deepest route wins; merge parents via
matchesor lose les. X-Robots-Tagviaheaders()fonctionne pour robots d’exploration que don’t render.- Remix v2’s APIs merged into React Router v7 (Dec 2024), même route API,
package renamed to
react-router. React Router is now on v8 (v7 encore security-supported). Remix 3 (beta) is a separate, newer framework — pas covered by ce page. - Resource routes:
sitemap[.xml].tsx,robots[.txt].tsx(brackets escape the dot). - Aucun dynamic rendering outils (Rendertron/Prerender.io) nécessaire — or recommended.
Vérifier ce que robots d’exploration en réalité recevoir
Remix renders on le serveur, but toujours confirmer the initial HTML plutôt que the post-hydration DOM in DevTools.
Vérifier the raw server HTML (content + tags are présent avant JS runs)
# Title, meta description, canonical — should all be in the raw response
curl -s https://example.com/blog/my-post/ | grep -iE '<title>|name="description"|rel="canonical"'
# Confirm JSON-LD is in the SSR'd head
curl -s https://example.com/blog/my-post/ | grep -i 'application/ld+json'Confirmer réel Code d’état HTTPs (aucun soft 404s, réel redirections)
# A missing page must return 404, not 200
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/blog/does-not-exist/
# A moved URL should return 301/302 with a Location header
curl -sI https://example.com/old-url/ | grep -iE 'HTTP/|location'Vérifier HTTP-level robots / cache headers from headers()
curl -sI https://example.com/private-route/ | grep -iE 'x-robots-tag|cache-control'A minimal robots.txt resource route
// app/routes/robots[.txt].tsx
export async function loader() {
return new Response(
`User-agent: *\nAllow: /\nSitemap: https://example.com/sitemap.xml\n`,
{ headers: { "Content-Type": "text/plain" } }
);
} Outils pour auditing a Remix site
curl/ View Source — the ground truth pour what’s in the initial SSR’d HTML (titles, description, canonical, JSON-LD) avant hydration. Don’t trust DevTools Elements alone — it montre the post-JS DOM.- Recherche Google Console — Inspection d’URL — voir how Googlebot crawled and rendered a unique Remix URL; pour SSR pages the served and rendered HTML devrait match.
- Résultats enrichis Tester — validate the JSON-LD vous emit via
"script:ld+json". - Ahrefs Site Audit — explorer the whole site pour manquant/duplicate meta (the nested-meta merge bug surfaces ici), broken canonicals, chaîne de redirectionss, and depth.
- Screaming Frog SEO Spider — a developer-friendly explorer to confirmer titles, canonicals, and code d’états à travers routes.
vite-bundle-visualizer— inspect client bundles (Remix uses Vite) to garder JS lean pour Core Web Vitals.- Bing Webmaster Outils — Inspection d’URL — vérifier Bingbot sees the SSR’d content.
Testez vos connaissances: Remix SEO
Five rapide questions on how Remix handles SEO. Pick an réponse pour chaque, alors vérifier.
Ressources utiles
My writing
- JavaScript SEO: A Definitive Guide — rendering, DOM parity, the most-restrictive-directive rule, and choosing a rendering mode — the framework-agnostic background pour everything Remix fait by par défaut.
- The Beginner’s Guide to SEO technique — où rendering and frameworks fit in the bigger picture.
My speaking
- How Search Fonctionne (SlideShare) — my walkthrough of exploration, rendering, indexation, and ranking. (My standing disclaimer s’applique: “This is my understanding of systems… not going to be 100% complete or accurate.”)
From autour the industry
- Remix docs —
metafunction — principal source pour per-route metadata andmatchesmerging. - Remix docs —
loaderandheaders— server données, thrown réponses, and HTTP headers. - React Router v7 announcement / React Router v8 / React Router docs — the Remix v2 merge, the current v8 release, and où the route API now lives (Remix 3 is a separate, newer product).
- Comprendre the JavaScript SEO basics (Google) — the rules Remix’s output is judged by: code d’états,
<a href>liens, SSR guidance. - Dynamic rendering (deprecated) (Google) — pourquoi Remix sites jamais besoin Rendertron/Prerender.io.
- web.dev — Rendering on the Web — the Chrome team’s CSR/SSR/SSG/hydration explainer; the conceptual backbone pour Remix’s server-first model.
- r/TechSEO — the community pour framework rendering/indexation debugging.
Journal des modifications
Mis à jour le 18 juil. 2026.
Résumé éditorial et détails enregistrés des changements.Détails des changements
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
Comparaison complète indisponible — aucun instantané antérieur n’a été archivé pour cette révision.