Skip to main content

Search Engine Optimization for Hydrogen

Optimizing Hydrogen for search engines and social media requires configuring the following things:

  1. Meta tags and descriptions
  2. sitemap.xml
  3. robots.txt

This guide walks you through the process of setting up each one.

Note

This isn't a comprehensive guide to SEO best practices. Check the Shopify blog for more resources on commerce SEO.


Hydrogen uses Remix's built-in meta features for SEO tags, and includes the getSeoMeta utility, which makes it easier and more consistent to render SEO meta tags.

Note

Remix Check out the Remix docs on meta exports for more details.

The getSeoMeta utility accepts SEO metadata about the current route, then renders the corresponding HTML meta tags in your document <head>:

getSeoMeta example input and output

/app/routes/example.jsx

export const meta = () => {
return getSeoMeta({
title: 'Example title',
});
};
<head>
<!-- ... -->
<title>Example title</title>
<meta property="og:title" content="Example title" />
<meta property="twitter:title" content="Example title" />
<!-- ... -->
</head>

It includes support for titles, descriptions, images, canonical URLs, JSON-LD and more. Check the getSeoMeta reference for a complete list of supported features.

The SEO data you want will vary by route. For example, you'll want to render different tags on a product page versus the home page. The following example code shows how the basic pattern applies across all your storefront routes:

Import and use getSeoMeta

/app/routes/root.jsx

import {getSeoMeta} from '@shopify/hydrogen';
// ...
export async function loader() {
return {
//...
// Return an SEO object in your loader data
seo: {
title: "Storefront name",
description: "Storefront description, including relevant keywords to help new customers find your page",
},
};
}

// Pass the loader data to the meta export
export const meta = ({data}) => {
// pass your SEO object to getSeoMeta()
return getSeoMeta(data.seo);
};
import {getSeoMeta} from '@shopify/hydrogen';
import {type MetaFunction} from '@react-router';
// ...
export async function loader({context}: LoaderFunctionArgs) {
return {
//...
// Return an SEO object in your loader data
seo: {
title: "Storefront name",
description: "Storefront description, including relevant keywords to help new customers find your page",
},
};
}

// Pass the loader data to the meta export
export const meta: MetaFunction<typeof loader> = ({data}) => {
// pass your SEO object to getSeoMeta()
return getSeoMeta(data.seo);
};

Anchor to Step 2: Merge SEO data from nested routesStep 2: Merge SEO data from nested routes

Often, two or more nested routes are returning SEO data. In general, you'll want to use the most specific SEO tags available for your route.

For example, if you're on the product page, you want to show a title and description of your product, not the store name and description from the root route.

The following code examples show how to return SEO data from a nested product route, then merge it with SEO data from the root route. By mapping over SEO data returned by all nested routes, The most specific SEO data "wins", overwriting SEO data from higher in the routing structure:

Merge SEO data from nested routes

/app/routes/root.jsx

import {getSeoMeta} from '@shopify/hydrogen';
// ...
export async function loader({context}) {
return {
//...
// Return basic shop SEO data
seo: {
title: "Storefront name",
description: "Storefront description, including relevant keywords to help new customers find your page",
},
};
}

export const meta = ({data}) => {
// Pass your SEO object to getSeoMeta()
return getSeoMeta(data.seo);
};

// Switch to the "Product handle route" to see how these relate
import {getSeoMeta} from '@shopify/hydrogen';
// ...
export async function loader({context}) {
const {product} = await context.storefront.query(/* GraphQL query */);
return {
//...
// Return product SEO data
seo: {
title: product.seo.title || product.title,
description: product.seo.description || product.description,
// ...this could also include image URLs, prices, and more
},
};
}

/// Pass all product loader data to the meta export
export const meta = ({matches}) => {
// Map data from all routes. More specific SEO data from nested routes
// overrides more general SEO data from parent routes.
return getSeoMeta(...matches.map((match) => match.data.seo));
};

Anchor to Step 3 (Optional): Intercept and override route SEO dataStep 3 (Optional): Intercept and override route SEO data

You can implement your own logic inside meta exports to customize the SEO metadata that each route returns.

As an example, by default Hydrogen removes query parameters from canonical URLs. If you wanted to add them back, the following is an example of how you could do that:

Override SEO data with custom logic

/app/routes/root.jsx

import {getSeoMeta} from '@shopify/hydrogen';
// ...
export const meta = ({data, location}) => {
return getSeoMeta(data.seo).map((meta) => {
if (meta.rel === 'canonical') {
return {
...meta,
// Overwrite the default value of meta.href to append the URL params
href: meta.href + location.search,
};
}
return meta;
});
};
import {getSeoMeta} from '@shopify/hydrogen';
import {type MetaFunction} from '@react-router';
// ...
export const meta: MetaFunction<typeof loader> = ({data, location}) => {
return getSeoMeta(data.seo).map((meta) => {
if (meta.rel === 'canonical') {
return {
...meta,
// Overwrite the default value of meta.href to append the URL params
href: meta.href + location.search,
};
}
return meta;
});
};

Hydrogen's base template includes sitemap.xml and sitemap.$type.$page.xml routes by default. If your project doesn't already have these files, then you can generate them with the following Shopify CLI command:

Terminal

npx shopify hydrogen generate route sitemap

By default, the sitemap files are cached for 24 hours.

  • When you add or remove pages, the sitemap is automatically updated within one day. Similarly, if you unpublish a product, then the product is removed automatically from the sitemap.

Hydrogen's base template includes a robots.txt route by default. If your project doesn't already have a robots.txt file, you can generate a new one with the Hydrogen CLI:

Terminal

npx shopify hydrogen generate route robots

By default, Hydrogen's robots.txt file is cached for 24 hours.

Anchor to robots.txt on Oxygenrobots.txt on Oxygen

If you deploy to Oxygen, then your robots.txt file is only served in your public production environment, and only if you have a custom domain set.

If you make a non-production deployment accessible with a shareable link or an auth bypass token, then Oxygen overrides the deployment's robots.txt file with a disallow rule for all bots and crawlers. This prevents exposing content prematurely, as well as potential SEO harm from duplicated content.



Was this page helpful?