Adding Canonical URLs to a Remix website

Remix is a React framework to create websites and single page applications (SPA). By default, it creates however only the essentials, and lacks Canonical URLs, which are important for search engine optimization (SEO). Luckily, they can be added with only a few lines as shown below.

Why are canonical URLs important?

An important aspect for basic (SEO) is to have a canonical URL on each page. Search engines typical only index the canonical URLs of a website. If a search engine realizes that you are publishing the same content at different pages with differen canonical URLs, it might penalize you for this and lower your ranking. So, if you want your site to be found through a search engine, make sure that your canonical URLs are correct.

To add a canonical URL, use a canonical tag with the correct link and add it to the header of your site

<html>
  <head>
    <link rel="canonical" href="https://www.example.com/my-page" />
    ...
  </head>
  ...
</html>

If the pages of your website would be accessible through only one URL, most search engine would be clever enough and would not require a dedicated canonical URL.

However, it can happen quickly that you end up with several URLs for the same page:

  • Your website is reachable under the plain hostname as well as under the www subdomain like example.com and www.example.com
  • Your website is reachable through http as well as https: http://example.com and https://example.com
  • Your website uses search/query paramters, either for tracking or for interaction: example.com?lang=en, example.com?lang=de, example.com?utm_source=linkedin.com are all the same to a search engine.
  • You might have somewhere a devlopment deployment with almost identical content.

How to create canonical URLs for Remix

Remix uses a lot of conventions to do the plumbing of your site. One easy but repetitive way of creating the canconical URLs, is to simply add it straight to your final route files.

Assuming, we want to add a canonical URL to example.com/my-page, add the following to app/routes/my-page.jsx:

export const links = () => [{
  rel: 'canonical',
  href: 'https://example.com/my-page'
}]

However, this is a) repetive and b) error-prone as you would need to update the URL everytime you move the route or change the host.

A more elegant solution is to use matches and handles.

The following example builds on our previous project with mobile-friendly menus. The code can be found on github.

git clone https://github.com/bielern/remix-tailwind-mobile-menu.git

First, create a function that can build a canonical URL based on the pathname. In components.jsx, add

// Replace the host with your "official" host
const host = "https://example.com"
export const canonicalLink = ({pathname}) => [{
  rel: 'canonical',
  href: `${host}${pathname}`
}]

Second, import the canonicalLink function in each route and export the handle with it. E.g. in about.jsx:

export const handle = {
  canonicalLink
}

Third and last, create a CanonicalLinks component in root.jsx that will add the canonical URL to the HTML body.

function CanonicalLinks() {
  const matches = useMatches()
  // The match m contains the pathname to construct the canonical URL
  return matches
    .filter(m => m?.handle?.canonicalLink)
    .flatMap(m => 
      m.handle.canonicalLink(m)
        .map(data => <link {...data} />)
    )
}

export default function App() {
  return (
    <html lang="en">
      <head>
        <Meta />
        <Links />
        <CanonicalLinks />
      </head>
      ...
    </html>

Now we can check the source that is sent to the browser and we see that the canonical URL changes.

Canonical URL tag for the home page for Remix created with matchers and handles

The canonical URL tag shows the correct URL depending on whether we are at Home ….

Canonical URL tag created automatically for Remix with matchers and handle

… or whether we are at About.

Conclusion

So, with a handful of changes, we can create canconical URLs needed for SEO in any Remix appliation that we have. You can use the same mechanism to also generate Open Graph tags important for sharing content. To create a sitemap or robots.txt, there are packages available.

Previous
Previous

A CRUD web app using Next.js 13, iron-session and Prisma

Next
Next

"Truncated ZIP file" error with Apache POI and akka-http