SEO Best Practices | Yext Hitchhikers Platform
Overview
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. Yext has loads of resources about SEO, so if you want more general information, check out this module .
This reference doc will explain the key features that Pages offers for developing with top-notch SEO.
SEO Checklist
This checklist is meant to serve as a starting point to ensure all of your pages satisfy these basic SEO criteria:
h1
tag- Each page has ONE relevant
h1
tag - The
h1
tag 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 (see below for detailed info)
- OG tags are included where appropriate to enhance social media presence (more info here )
- Canonical URL
- Use of 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 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:
_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, which 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>`; };
getHeadConfig
exportThe
getHeadConfig
export can be used to append custom configuration on a per-template basis. For each template, PagesJS will inject the contents ofgetHeadConfig
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! The example below gives an example of a simple schema in json/ld
format. Check out the schema configuration in the default export
below for a simple example.
sites-rendered-output
into the schema validator.
Note a few things about the example:
- It uses two imports :
react-schemaorg
andschema-dts
, which make formatting your schema injson/ld
very simple. - The
JsonLd
object should be included in the TSX returned from your default export. The various address fields will be populated at build-time by the
address
object which is 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 ( <> // Start Configuration of Schema <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, }, }} /> // End Configuration of Schema <h1>A dentist site called {name} </h1> </body> </> ); }; export default Index;