SaketSingh

SitecoreAI (XM Cloud): Implement SEO Meta Tags

👤Saket Singh
|
📅March 19, 2026
|
⏱️7 min read
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
We'll use the same Sitecore component architecture: 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:

  1. Navigate to /sitecore/content/Settings
  2. Create folder: Twitter Card Types
  3. 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 implementing NoIndex/NoFollow, you just need to update the existing MetaTags component.

Update Component in Sitecore

  1. The MetaTags rendering already exists at: /sitecore/layout/Renderings/Project/<Your Project Name>/Components/MetaTags
  2. No changes needed - it will automatically pick up the new fields!

Verify Partial Design

  1. Go to: /sitecore/layout/Partial Designs/Project/<Your Project Name>/MetaTags
  2. Verify MetaTags component is in the headless-metatags placeholder
  3. It should already be in all your Page Designs from 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:

  1. Comprehensive SEO meta tags
  2. Full Open Graph support for social sharing
  3. Twitter Cards with type selection
  4. Smart fallback system (minimal data entry)
  5. NoIndex/NoFollow integration
  6. Image field handling
  7. Droplink support
  8. 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


Share this post: