How to add canonical url to Remix 💿
Tags: remix, seo, webdev, tutorial
Published: 2021-12-25 03:41:11

> This article has originally been published to [canrau.com](https://www.canrau.com/en/how-to-add-canonical-url-to-remix)

## Using `loader` data

This one is probably my fav, as it doesn't require any other function than the most probably already present `loader`. And because it's part of the loader it gives me full access to the already fetched content 🥰

```ts
import { homepage } from "/package.json"; // or import from some kind of "/config"
export const loader: LoaderFunction = async ({ params }) => {
  // [..]
  const { frontmatter, code } = await bundleMDX();
  // [..]
  const canonical = `${homepage}/${frontmatter?.lang}${frontmatter?.slug}`;
  return { frontmatter, code, canonical };
};
```

Then in my `root.tsx` I have the following `Document` component, where especially lines 12 - 14 and line 23 are relevant.

```tsx
function Document({
  children,
  title,
  lang,
}: {
  children: ReactNode;
  title?: string;
  lang: string;
}) {
  // use `export const handle = { hydrate: true };` in any route to enable JS
  const includeScripts = useShouldHydrate(); // from remix-utils
  const matches = useMatches();
  const match = matches.find((match) => match.data && match.data.canonical);
  const canonical = match?.data.canonical;

  return (
    <html lang={lang} className="dark scroll-smooth">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        {title ? <title>{title}</title> : null}
        <Meta />
        {!!canonical && <link rel="canonical" href={canonical} />}
        <Links />
        <link
          rel="alternate"
          type="application/rss+xml"
          href={`${rootUrl}/${lang}/feed.xml`}
          title="Can Rau's XML Feed"
        />
        <link
          rel="alternate"
          type="application/feed+json"
          href={`${rootUrl}/${lang}/feed.json`}
          title="Can Rau's JSON Feed"
        />
      </head>
      <body className="dark:bg-gray-900">
        {children}
        <ScrollRestoration />
        {includeScripts && <Scripts />}
        {process.env.NODE_ENV === "development" && <LiveReload />}
      </body>
    </html>
  );
}
```

> Note: More about the `<link rel="alternate" />` in my other article [RSS in Remix](/en/rss-in-remix)

More about useMatches in the [Remix Package docs](https://remix.run/docs/en/v1/api/remix#usematches) and in the [Disabling Javscript docs](https://remix.run/docs/en/v1/guides/disabling-javascript)

Remix used to provide the `loader` data to `links`, but they had to [remove it for prefetching](https://discord.com/channels/770287896669978684/771068344320786452/907715068303642655)

## Related links

- [Mistake 5: rel=canonical in the <body/> - 5 common mistakes with rel=canonical](https://developers.google.com/search/blog/2013/04/5-common-mistakes-with-relcanonical#mistake-5:-rel=canonical-in-the-body)
- [​Canonical outside of head](https://sitebulb.com/hints/indexability/canonical-outside-of-head/)
- [Canonical URL / Location Checker](https://www.seoreviewtools.com/canonical-url-location-checker/)