SitecoreAI (XM Cloud): Implement SEO Meta Tags

In my previous post, we implemented NoIndex and NoFollow meta tags. Now let's expand that into a complete meta tags system that handles everything your marketing team needs:
- SEO meta tags (title, description, keywords)
- Open Graph for Facebook and LinkedIn sharing
- Twitter Cards
- Custom meta attributes
Placeholder → Partial Design → Page Design. Let's build it.
What We're Building
A unified MetaTags component that content editors can manage entirely through Sitecore, with zero code deployments needed for content changes.
Content editors will control:
- Page title and description for search engines
- Social sharing appearance on Facebook/LinkedIn
- Twitter card display
- Additional custom meta tags
⚙️ Step 1: Extend Template Fields
Let's add all the fields we need to your existing_Base Metadata template.
Complete Field Set: Add these sections and fields to
/sitecore/templates/Project/<Your Project Name>/_Base Metadata:
# /serialization/templates/Project/<Your Project Name>/_Base Metadata.yml Path: /sitecore/templates/Project/<Your Project Name>/_Base Metadata Sections: # Basic SEO Section (expand existing or create new) - Name: SEO Settings Fields: - Name: MetaTitle Type: Single-Line Text Title: Meta Title Help: "Page title for search engines (50-60 characters)" - Name: MetaDescription Type: Multi-Line Text Title: Meta Description Help: "Description for search results (150-160 characters)" - Name: MetaKeywords Type: Single-Line Text Title: Meta Keywords Help: "Comma-separated keywords (legacy, optional)" - Name: NoIndex Type: Checkbox Title: No Index Help: "Prevent search engines from indexing this page" - Name: NoFollow Type: Checkbox Title: No Follow Help: "Prevent search engines from following links on this page" # Social Media / Open Graph Section - Name: Social Sharing Fields: - Name: OpenGraphTitle Type: Single-Line Text Title: OG Title Help: "Title for social shares (falls back to Meta Title)" - Name: OpenGraphDescription Type: Multi-Line Text Title: OG Description Help: "Description for social shares (falls back to Meta Description)" - Name: OpenGraphImage Type: Image Title: OG Image Help: "Share image - recommended size: 1200x630px" - Name: OpenGraphType Type: Single-Line Text Title: OG Type Help: "Content type (website, article, etc.)" - Name: OpenGraphSiteName Type: Single-Line Text Title: Site Name Help: "Your site name" # Twitter Section - Name: Twitter Fields: - Name: TwitterTitle Type: Single-Line Text Title: Twitter Title Help: "Title for Twitter (falls back to OG Title)" - Name: TwitterDescription Type: Multi-Line Text Title: Twitter Description Help: "Description for Twitter (falls back to OG Description)" - Name: TwitterImage Type: Image Title: Twitter Image Help: "Twitter share image - recommended: 1200x628px" - Name: TwitterCardType Type: Droplink Title: Twitter Card Type Help: "Select card display type" Source: "/sitecore/content/Settings/Twitter Card Types"
Create Twitter Card Type Settings
Create the dropdown options:
- Navigate to
/sitecore/content/Settings - Create folder:
Twitter Card Types - Inside, create two items (use the Item template):
Item 1:
- Name:
Summary - Add field:
Value = summary
Item 2:
- Name:
Summary Large Image - Add field:
Value = summary_large_image
Deploy fields:
dotnet sitecore ser push
🧱 Step 2: Create Comprehensive TypeScript Interfaces
Update your type definitions to include all metadata fields:
// src/types/metadata.ts import { Field, ImageField } from '@sitecore-jss/sitecore-jss-nextjs'; /** * Droplink field structure from Sitecore */ interface DroplinkField { fields: { Value: { value: string; }; }; } /** * All metadata fields available on pages */ export interface MetaTagsFields { // Basic SEO MetaTitle?: Field<string>; MetaDescription?: Field<string>; MetaKeywords?: Field<string>; Title?: Field<string>; // Fallback from page title field // Robots NoIndex?: Field<boolean>; NoFollow?: Field<boolean>; // Open Graph / Social Sharing OpenGraphTitle?: Field<string>; OpenGraphDescription?: Field<string>; OpenGraphImage?: ImageField; OpenGraphType?: Field<string>; OpenGraphSiteName?: Field<string>; // Twitter TwitterTitle?: Field<string>; TwitterDescription?: Field<string>; TwitterImage?: ImageField; TwitterCardType?: DroplinkField; } /** * Props for MetaTags component */ export interface MetaTagsProps { fields?: MetaTagsFields; }
🏗️ Step 3: Build the Complete MetaTags Component
Now let's create the full component with all meta tag types:
// src/components/<Your Project Name>/MetaTags.tsx import React from 'react'; import Head from 'next/head'; import { Field, ImageField } from '@sitecore-jss/sitecore-jss-nextjs'; /** * Droplink field structure */ interface DroplinkField { fields: { Value: { value: string; }; }; } /** * All metadata fields */ interface MetaTagsFields { // Basic SEO MetaTitle?: Field<string>; MetaDescription?: Field<string>; MetaKeywords?: Field<string>; Title?: Field<string>; // Robots NoIndex?: Field<boolean>; NoFollow?: Field<boolean>; // Open Graph OpenGraphTitle?: Field<string>; OpenGraphDescription?: Field<string>; OpenGraphImage?: ImageField; OpenGraphType?: Field<string>; OpenGraphSiteName?: Field<string>; // Twitter TwitterTitle?: Field<string>; TwitterDescription?: Field<string>; TwitterImage?: ImageField; TwitterCardType?: DroplinkField; } /** * Component props */ interface MetaTagsProps { fields?: MetaTagsFields; } /** * MetaTags Component * Comprehensive meta tag management for SEO and social sharing */ const MetaTags = ({ fields }: MetaTagsProps): JSX.Element | null => { if (!fields) { return null; } // --- NoIndex / NoFollow Logic --- const robotsContent = [ fields.NoIndex?.value && 'noindex', fields.NoFollow?.value && 'nofollow' ].filter(Boolean).join(','); // --- Basic SEO Tags --- const seoTags = [ { name: 'description', content: fields.MetaDescription?.value }, { name: 'keywords', content: fields.MetaKeywords?.value }, ]; // --- Open Graph Tags (with smart fallbacks) --- const ogTags = [ { property: 'og:title', content: fields.OpenGraphTitle?.value || fields.MetaTitle?.value || fields.Title?.value }, { property: 'og:description', content: fields.OpenGraphDescription?.value || fields.MetaDescription?.value }, { property: 'og:image', content: fields.OpenGraphImage?.value?.src }, { property: 'og:type', content: fields.OpenGraphType?.value || 'website' }, { property: 'og:site_name', content: fields.OpenGraphSiteName?.value }, ]; // --- Twitter Tags (with cascading fallbacks) --- const twitterTags = [ { property: 'twitter:title', content: fields.TwitterTitle?.value || fields.OpenGraphTitle?.value || fields.MetaTitle?.value }, { property: 'twitter:description', content: fields.TwitterDescription?.value || fields.OpenGraphDescription?.value || fields.MetaDescription?.value }, { property: 'twitter:image', content: fields.TwitterImage?.value?.src || fields.OpenGraphImage?.value?.src }, { property: 'twitter:card', content: fields.TwitterCardType?.fields?.Value?.value || 'summary_large_image' }, ]; return ( <Head> {/* Robots meta tag */} {robotsContent && <meta name="robots" content={robotsContent} />} {/* Basic SEO meta tags */} {seoTags.map((tag, index) => tag.content ? ( <meta name={tag.name} content={tag.content} key={`seo-${index}`} /> ) : null )} {/* Open Graph meta tags */} {ogTags.map((tag, index) => tag.content ? ( <meta property={tag.property} content={tag.content} key={`og-${index}`} /> ) : null )} {/* Twitter meta tags */} {twitterTags.map((tag, index) => tag.content ? ( <meta property={tag.property} content={tag.content} key={`twitter-${index}`} /> ) : null )} </Head> ); }; export default MetaTags;
🛠️ Step 4: Sitecore Setup (Same as Before)
Since you already have the infrastructure from implementingNoIndex/NoFollow, you just need to update the existing MetaTags component.
Update Component in Sitecore
- The MetaTags rendering already exists at:
/sitecore/layout/Renderings/Project/<Your Project Name>/Components/MetaTags - No changes needed - it will automatically pick up the new fields!
Verify Partial Design
- Go to:
/sitecore/layout/Partial Designs/Project/<Your Project Name>/MetaTags - Verify MetaTags component is in the
headless-metatagsplaceholder - It should already be in all your
Page Designsfrom the previous setup
No additional Sitecore configuration needed.
🔌Step 5: Update Component Factory (If Needed)
If you created a new MetaTags file, update the component factory:
// src/temp/componentFactory.ts import MetaTags from 'components/<Your Project Name>/MetaTags'; const components = new Map(); components.set('MetaTags', MetaTags); // ... other components export default defaultComponentFactory(components);
📐 Step 6: Your Layout.tsx is Already Set
Your Layout component doesn't need any changes. It already has:
⚡Wrapping Up
You now have a complete, enterprise-grade meta tags system in SitecoreAI (XM Cloud)
✨ What we built:
- Comprehensive SEO meta tags
- Full Open Graph support for social sharing
- Twitter Cards with type selection
- Smart fallback system (minimal data entry)
- NoIndex/NoFollow integration
- Image field handling
- Droplink support
- Production-ready TypeScript code
Now your marketing team can manage all meta tags without touching code, your social shares look professional, and your SEO is rock solid