SEO is one of the most important features of a successful web presence, and Pages enables you to easily build a highly performant site that will succeed in search.
This reference doc explains the key features that Pages offers for developing with top-notch SEO.
SEO Checklist
This checklist serves as a starting point to ensure all of your pages satisfy basic SEO criteria:
-
h1tag- Each page has ONE relevant
h1tag - The
h1tag should normally be the title of your page
- Each page has ONE relevant
-
Meta tags / OG tags / title tags (see below for Pages configuration)
- Tags are present with no spelling errors
- OG tags are included where appropriate to enhance social media presence (more info at ogp.me)
-
Canonical URL
- Use canonical URLs where appropriate — learn more here
-
Schema (see below for Pages configuration)
- Tested on Google Rich Results Test
- No Schema Errors as validated on Schema Validator
- If the page represents a location, then name, address, phone, map, and description are all tagged
- NO duplicate tags
Head Configuration and Meta Tags
Yext makes it easy to power HTML <head> tags across your website with dynamic content from your CMS.
The <head> element contains metadata about your web page, such as the title, character set, styles, scripts, and CSS style sheets. Metadata provides browsers and search engines with technical information about the web page, and is a crucial component of your SEO strategy.
Pages offers two entry-points in your repo for <head> configuration:
1. _server.tsx
The _server.tsx file allows you to configure how your templates will be rendered on the server (refer to the Client-Server Templates reference doc for more information). This can be used to create a global <head> tag that will be used by all templates in your project.
The example below shows how to add a favicon to the <head> tag, as well as pull data from a _site object to power a script tag.
import * as ReactDOMServer from "react-dom/server";
import * as React from "react";
import { PageContext } from "@yext/pages";
import Favicon from "../assets/images/yext-favicon.ico";
export { render };
const render = async (pageContext: PageContext<any>) => {
const { Page, pageProps } = pageContext;
const viewHtml = ReactDOMServer.renderToString(<Page {...pageProps} />);
const customField = pageProps.document._site.c_customField;
return `<!DOCTYPE html>
<html lang="<!--app-lang-->">
<head>
<link rel="icon" type="image/x-icon" href=${Favicon}>
<script>
thirdPartyAnalytics(${customField})
</script>
</head>
<body>
<div id="reactele">${viewHtml}</div>
</body>
</html>`;
};
2. getHeadConfig export
The getHeadConfig export can be used to append custom configuration on a per-template basis. For each template, PagesJS will inject the contents of getHeadConfig at the top of the <head> configuration in _server.tsx.
The example below provides a simple meta tag with a title and description, Open Graph tags for image and URL, and canonical URL.
/**
* This allows the user to define a function which will take in their template
* data and produce a HeadConfig object. When the site is generated, the HeadConfig
* will be used to generate the inner contents of the HTML document's <head> tag.
* This can include the title, meta tags, script tags, etc.
*/
export const getHeadConfig: GetHeadConfig<TemplateRenderProps> = ({
document,
}): HeadConfig => {
return {
title: document.name, // Page Title
charset: "UTF-8",
viewport: "width=device-width, initial-scale=1",
tags: [
{
type: "meta", // Meta Tag (Description)
attributes: {
name: "description",
description: "This site was generated by the Yext SSG",
},
},
{
type: "meta", // Open Graph: An image URL which should represent your object within the graph
attributes: {
name: "og:image",
description: "https://images.google.com/",
},
},
{
type: "meta", // Open Graph: The canonical URL of your object that will be used as its permanent ID in the graph
attributes: {
property: "og:url",
content: xxxxxxx,
},
},
{
type: "link",
attributes: {
rel: "canonical",
href: document.,
},
}
],
};
};
Schema
Schema helps search engines more effectively understand your page content and provide rich search results. Refer to our schema module for a full overview of the benefits.
Using the streams data architecture, it is possible to generate dynamic schema objects without any client-side logic.
Note: Always test your schema changes locally using the Schema.org validator. This tool allows you to verify whether or not you've generated a valid schema object. During local development, you can build your site and then copy the HTML for a given page from the
sites-rendered-outputinto the schema validator.
The example below gives a simple schema in json/ld format. Note a few things:
- It uses two imports —
react-schemaorgandschema-dts— which make formatting your schema injson/ldvery simple. - The
JsonLdobject should be included in the TSX returned from your default export. - The various address fields will be populated at build-time by the
addressobject returned by the streams.
import {
GetHeadConfig,
GetPath,
HeadConfig,
Template,
TemplateConfig,
TemplateProps,
TemplateRenderProps,
} from "@yext/pages";
import * as React from "react";
import { JsonLd } from "react-schemaorg";
import { Dentist } from "schema-dts";
export const config: TemplateConfig = {
stream: {
$id: "index-stream",
filter: {
entityIds: ["location"],
},
fields: [
"name",
"address",
],
localization: {
locales: ["en"]
},
},
};
export const getPath: GetPath<TemplateProps> = ({ document }) => {
return `index.html`;
};
const Index: Template<TemplateRenderProps> = ({
document,
}) => {
const {
name,
address,
} = document;
return (
<>
<body>
<JsonLd<Dentist>
item={{
"@context": "https://schema.org",
"@type": "Dentist",
name,
address: {
"@type": "PostalAddress",
streetAddress: address.line1,
addressLocality: address.city,
addressRegion: address.region,
postalCode: address.postalCode,
addressCountry: address.countryCode,
},
}}
/>
<h1>A dentist site called {name} </h1>
</body>
</>
);
};
export default Index;