Package detail

next-seo

garmeeh1.6m7.0.0

SEO plugin for Next.js projects

readme

Outrank

Get traffic and outrank competitors with Backlinks & SEO-optimized content while you sleep! I've been keeping a close eye on this new tool and it seems to be gaining a lot of traction and delivering great results. Try it now!

image

Have you seen the new Next.js newsletter?

NextjsWeekly banner

Next SEO

npm npm version TypeScript License

Next SEO is a plugin that makes managing your SEO easier in Next.js projects. It provides components for structured data (JSON-LD) that helps search engines understand your content better.

📋 Table of Contents

<summary>Click to expand</summary> - Quick Start - Installation - Basic Usage - Components by Category - Articles & Content - Commerce & Products - Local Business - Media & Entertainment - Education & FAQ - Reviews & Ratings - Navigation & Structure - Events & Activities - Employment - Real Estate - Software & Apps - Creating Custom Components - Pages Router Support - Contributing

🚀 Quick Start

Installation

npm install next-seo
# or
yarn add next-seo
# or
pnpm add next-seo
# or
bun add next-seo

Basic Usage

import { ArticleJsonLd } from "next-seo";

export default function BlogPost() {
  return (
    <>
      <ArticleJsonLd
        headline="Getting Started with Next SEO"
        datePublished="2024-01-01T08:00:00+00:00"
        author="John Doe"
        image="https://example.com/article-image.jpg"
        description="Learn how to improve your Next.js SEO"
      />
      <article>
        <h1>Getting Started with Next SEO</h1>
        {/* Your content */}
      </article>
    </>
  );
}

Note: For standard meta tags (<meta>, <title>), use Next.js's built-in generateMetadata function.

Pages Router Support: If you're using Next.js Pages Router, import components from next-seo/pages. See the Pages Router documentation for details.

Support This Project

Feel like supporting this free plugin?

It takes a lot of time to maintain an open source project so any small contribution is greatly appreciated.

Coffee fuels coding ☕️

Buy Me A Coffee

Components

ArticleJsonLd

The ArticleJsonLd component helps you add structured data for articles, blog posts, and news articles to improve their appearance in search results.

Basic Usage

import { ArticleJsonLd } from "next-seo";

export default function ArticlePage() {
  return (
    <>
      <ArticleJsonLd
        headline="My Amazing Article"
        datePublished="2024-01-01T08:00:00+08:00"
        author="John Doe"
        image="https://example.com/article-image.jpg"
        description="This article explains amazing things about Next.js SEO"
      />
      <article>
        <h1>My Amazing Article</h1>
        {/* Article content */}
      </article>
    </>
  );
}

Advanced Example with Multiple Authors

<ArticleJsonLd
  type="NewsArticle"
  headline="Breaking: Next SEO v7 Released"
  url="https://example.com/news/next-seo-v7"
  datePublished="2024-01-01T08:00:00+08:00"
  dateModified="2024-01-02T10:00:00+08:00"
  author={[
    {
      "@type": "Person",
      name: "Jane Smith",
      url: "https://example.com/authors/jane",
    },
    "John Doe", // Can mix objects and strings
  ]}
  image={[
    "https://example.com/images/16x9.jpg",
    "https://example.com/images/4x3.jpg",
    "https://example.com/images/1x1.jpg",
  ]}
  publisher={{
    "@type": "Organization",
    name: "Example News",
    logo: "https://example.com/logo.png",
  }}
  isAccessibleForFree={true}
/>

Blog Posting Example

<ArticleJsonLd
  type="BlogPosting"
  headline="10 Tips for Better SEO"
  url="https://example.com/blog/seo-tips"
  datePublished="2024-01-01T08:00:00+08:00"
  author={{
    "@type": "Organization",
    name: "SEO Experts Inc.",
    url: "https://example.com",
  }}
  image={{
    "@type": "ImageObject",
    url: "https://example.com/blog-hero.jpg",
    width: 1200,
    height: 630,
    caption: "SEO Tips Illustration",
  }}
  description="Learn the top 10 tips to improve your website's SEO"
  mainEntityOfPage={{
    "@type": "WebPage",
    "@id": "https://example.com/blog/seo-tips",
  }}
/>

Props

Property Type Description
type `"Article" \ "NewsArticle" \ "BlogPosting" \ "Blog"` The type of article. Defaults to "Article"
headline string Required. The headline of the article
url string The canonical URL of the article
author `string \ Person \ Organization \ Author[]` The author(s) of the article
datePublished string ISO 8601 date when the article was published
dateModified string ISO 8601 date when the article was last modified
image `string \ ImageObject \ (string \ ImageObject)[]` Article images. Google recommends multiple aspect ratios
publisher Organization The publisher of the article
description string A short description of the article
isAccessibleForFree boolean Whether the article is accessible for free
mainEntityOfPage `string \ WebPage` Indicates the article is the primary content of the page
scriptId string Custom ID for the script tag
scriptKey string Custom key prop for React

Best Practices

  1. Always include images: Google strongly recommends including high-resolution images with multiple aspect ratios (16x9, 4x3, 1x1)
  2. Use ISO 8601 dates: Include timezone information for accuracy
  3. Multiple authors: List all authors when applicable
  4. Publisher logo: Include a logo for NewsArticle type
  5. Update dateModified: Keep this current when updating content

↑ Back to Components

ClaimReviewJsonLd

The ClaimReviewJsonLd component helps you add structured data for fact-checking articles that review claims made by others. This enables a summarized version of your fact check to display in Google Search results.

Basic Usage

import { ClaimReviewJsonLd } from "next-seo";

export default function FactCheckPage() {
  return (
    <>
      <ClaimReviewJsonLd
        claimReviewed="The world is flat"
        reviewRating={{
          ratingValue: 1,
          bestRating: 5,
          worstRating: 1,
          alternateName: "False",
        }}
        url="https://example.com/fact-check/flat-earth"
        author="Fact Check Team"
      />
      <article>
        <h1>Fact Check: The World is Flat</h1>
        {/* Your fact check content */}
      </article>
    </>
  );
}

Props

Property Type Description
claimReviewed string Required. A short summary of the claim being evaluated (keep under 75 characters)
reviewRating object Required. The assessment of the claim with rating value and textual rating
url string Required. Link to the page hosting the full fact check article
author `string \ Organization \ Person` The publisher of the fact check article
itemReviewed Claim Detailed information about the claim being reviewed
scriptId string Custom ID for the script tag
scriptKey string Custom key for script identification

Review Rating Properties

Property Type Description
alternateName string Required. The truthfulness rating as human-readable text (e.g., "False", "Mostly true")
ratingValue number Required. Numeric rating (closer to bestRating = more true)
bestRating number Best value in the rating scale (must be greater than worstRating)
worstRating number Worst value in the rating scale (minimum value of 1)
name string Alternative to alternateName (use alternateName instead)

Advanced Example with Claim Details

<ClaimReviewJsonLd
  claimReviewed="Climate change is not real"
  reviewRating={{
    ratingValue: 1,
    bestRating: 5,
    worstRating: 1,
    alternateName: "Pants on Fire",
  }}
  url="https://example.com/fact-check/climate-denial"
  author={{
    name: "Climate Facts Organization",
    url: "https://example.com",
    logo: "https://example.com/logo.jpg",
  }}
  itemReviewed={{
    author: {
      name: "Climate Denial Institute",
      sameAs: "https://climatedenial.example.com",
    },
    datePublished: "2024-06-20",
    appearance: {
      url: "https://example.com/original-claim",
      headline: "The Great Climate Hoax",
      datePublished: "2024-06-22",
      author: "John Doe",
      publisher: {
        name: "Denial News",
        logo: "https://example.com/denial-logo.jpg",
      },
    },
  }}
/>

Best Practices

  1. Clear ratings: Use descriptive alternateName values that clearly indicate the verdict
  2. Claim summary: Keep claimReviewed concise (under 75 characters) to prevent wrapping
  3. Full context: Include itemReviewed when possible to provide claim origin details
  4. Consistent scale: Use a consistent rating scale across all your fact checks
  5. Author credibility: Clearly identify your fact-checking organization

↑ Back to Components

CreativeWorkJsonLd

The CreativeWorkJsonLd component helps you add structured data for various types of creative content, with special support for marking paywalled or subscription-based content. This enables Google to differentiate paywalled content from cloaking practices.

Basic Usage

import { CreativeWorkJsonLd } from "next-seo";

export default function ArticlePage() {
  return (
    <>
      <CreativeWorkJsonLd
        type="Article"
        headline="Premium Article"
        datePublished="2024-01-01T08:00:00+08:00"
        author="John Doe"
        description="This premium article requires a subscription"
        isAccessibleForFree={false}
        hasPart={{
          isAccessibleForFree: false,
          cssSelector: ".paywall",
        }}
      />
      <article>
        <h1>Premium Article</h1>
        <div className="non-paywall">Free preview content here...</div>
        <div className="paywall">
          Premium content that requires subscription...
        </div>
      </article>
    </>
  );
}

Props

Property Type Description
type `"CreativeWork" \ "Article" \ "NewsArticle" \ "Blog" \ "BlogPosting" \ "Comment" \ ...` The type of creative work. Defaults to "CreativeWork"
headline string The headline of the content (used for Article types)
name string The name of the content (alternative to headline)
url string URL of the content
author `string \ Person \ Organization \ Array` Author(s) of the content
datePublished string ISO 8601 publication date
dateModified string ISO 8601 modification date
image `string \ ImageObject \ Array` Image(s) associated with the content
publisher `string \ Organization \ Person` Publisher of the content
description string Description of the content
isAccessibleForFree boolean Whether the content is free or requires payment/subscription
hasPart `WebPageElement \ WebPageElement[]` Marks specific sections as paywalled
mainEntityOfPage `string \ WebPage` The main page for this content
scriptId string Custom ID for the script tag
scriptKey string Custom key for script identification

WebPageElement Properties (for hasPart)

Property Type Description
isAccessibleForFree boolean Required. Whether this section is free (false)
cssSelector string Required. CSS class selector (e.g., ".paywall")

Marking Paywalled Content

<CreativeWorkJsonLd
  type="NewsArticle"
  headline="Breaking News: Premium Coverage"
  datePublished="2024-01-01T08:00:00+00:00"
  isAccessibleForFree={false}
  hasPart={{
    isAccessibleForFree: false,
    cssSelector: ".premium-content",
  }}
/>

Multiple Paywalled Sections

<CreativeWorkJsonLd
  type="Article"
  headline="In-Depth Analysis"
  datePublished="2024-01-01T08:00:00+00:00"
  isAccessibleForFree={false}
  hasPart={[
    {
      isAccessibleForFree: false,
      cssSelector: ".section1",
    },
    {
      isAccessibleForFree: false,
      cssSelector: ".section2",
    },
  ]}
/>

Different CreativeWork Types

// Blog with subscription content
<CreativeWorkJsonLd
  type="Blog"
  name="Premium Tech Blog"
  description="Technology insights for subscribers"
  isAccessibleForFree={false}
/>

// Comment
<CreativeWorkJsonLd
  type="Comment"
  text="Great article!"
  author="Jane Smith"
  datePublished="2024-01-01T10:00:00+00:00"
/>

// Course with provider
<CreativeWorkJsonLd
  type="Course"
  name="Advanced Programming"
  provider="Tech University"
  description="Learn advanced programming concepts"
  isAccessibleForFree={false}
/>

// Review with rating
<CreativeWorkJsonLd
  type="Review"
  name="Product Review"
  itemReviewed="Amazing Gadget"
  reviewRating={{
    ratingValue: 4.5,
    bestRating: 5,
  }}
  author="Tech Reviewer"
/>

Best Practices

  1. Use specific types: Choose the most specific CreativeWork type (Article, NewsArticle, etc.) when applicable
  2. Mark paywalled sections: Use hasPart with cssSelector to identify paywalled content sections
  3. Class selectors only: Only use class selectors (e.g., ".paywall") for cssSelector, not IDs or other selectors
  4. Consistent selectors: Ensure your HTML classes match the cssSelector values exactly
  5. Complete metadata: Include as much metadata as possible (author, dates, images) for better search results

↑ Back to Components

RecipeJsonLd

The RecipeJsonLd component helps you add structured data for recipes to improve their appearance in search results with rich snippets that can include ratings, cooking times, and images.

Basic Usage

import { RecipeJsonLd } from "next-seo";

export default function RecipePage() {
  return (
    <>
      <RecipeJsonLd
        name="Simple Chocolate Chip Cookies"
        image="https://example.com/cookies.jpg"
        description="Classic chocolate chip cookies that are crispy on the outside and chewy on the inside"
        author="Baker Jane"
        datePublished="2024-01-01T08:00:00+00:00"
        prepTime="PT20M"
        cookTime="PT12M"
        totalTime="PT32M"
        recipeYield="24 cookies"
        recipeCategory="dessert"
        recipeCuisine="American"
        recipeIngredient={[
          "2 1/4 cups all-purpose flour",
          "1 cup butter, softened",
          "3/4 cup granulated sugar",
          "3/4 cup packed brown sugar",
          "2 large eggs",
          "2 teaspoons vanilla extract",
          "1 teaspoon baking soda",
          "1 teaspoon salt",
          "2 cups chocolate chips",
        ]}
        recipeInstructions={[
          "Preheat oven to 375°F (190°C)",
          "Mix flour, baking soda, and salt in a bowl",
          "In another bowl, cream butter and sugars until fluffy",
          "Beat in eggs and vanilla",
          "Gradually blend in flour mixture",
          "Stir in chocolate chips",
          "Drop by rounded tablespoons onto ungreased cookie sheets",
          "Bake for 9 to 11 minutes or until golden brown",
        ]}
      />
      <article>
        <h1>Simple Chocolate Chip Cookies</h1>
        {/* Recipe content */}
      </article>
    </>
  );
}

Advanced Example with Structured Instructions and Nutrition

<RecipeJsonLd
  name="Gourmet Lasagna"
  image={[
    "https://example.com/lasagna-16x9.jpg",
    "https://example.com/lasagna-4x3.jpg",
    "https://example.com/lasagna-1x1.jpg",
  ]}
  description="A rich and hearty lasagna with layers of meat sauce, cheese, and pasta"
  author={{
    "@type": "Organization",
    name: "The Italian Kitchen",
    url: "https://example.com",
  }}
  datePublished="2024-01-15T10:00:00+00:00"
  url="https://example.com/recipes/gourmet-lasagna"
  prepTime="PT45M"
  cookTime="PT1H"
  totalTime="PT1H45M"
  recipeYield={8}
  recipeCategory="main course"
  recipeCuisine="Italian"
  keywords="lasagna, italian, pasta, cheese"
  recipeIngredient={[
    "1 pound ground beef",
    "1 onion, chopped",
    "2 cloves garlic, minced",
    "1 can (28 oz) crushed tomatoes",
    "2 cans (6 oz each) tomato paste",
    "16 oz ricotta cheese",
    "1 egg",
    "12 lasagna noodles",
    "16 oz mozzarella cheese, shredded",
  ]}
  recipeInstructions={[
    {
      "@type": "HowToStep",
      name: "Prepare the meat sauce",
      text: "Brown ground beef with onion and garlic. Add tomatoes and tomato paste. Simmer for 30 minutes.",
    },
    {
      "@type": "HowToStep",
      name: "Prepare cheese mixture",
      text: "Mix ricotta cheese with egg and half of the mozzarella",
    },
    {
      "@type": "HowToStep",
      name: "Assemble lasagna",
      text: "Layer meat sauce, noodles, and cheese mixture in a 9x13 pan. Repeat layers.",
    },
    {
      "@type": "HowToStep",
      name: "Bake",
      text: "Cover with foil and bake at 375°F for 45 minutes. Remove foil, add remaining mozzarella, and bake 15 more minutes.",
    },
  ]}
  nutrition={{
    "@type": "NutritionInformation",
    calories: "450 calories",
    proteinContent: "28g",
    carbohydrateContent: "35g",
    fatContent: "22g",
    saturatedFatContent: "10g",
    sodiumContent: "680mg",
    fiberContent: "3g",
    servingSize: "1 piece (1/8 of recipe)",
  }}
  aggregateRating={{
    "@type": "AggregateRating",
    ratingValue: 4.7,
    ratingCount: 234,
    reviewCount: 189,
  }}
  video={{
    "@type": "VideoObject",
    name: "How to Make Gourmet Lasagna",
    description: "Watch our chef prepare this delicious lasagna step by step",
    thumbnailUrl: "https://example.com/lasagna-video-thumb.jpg",
    contentUrl: "https://example.com/videos/lasagna-tutorial.mp4",
    embedUrl: "https://example.com/embed/lasagna-tutorial",
    uploadDate: "2024-01-10T08:00:00+00:00",
    duration: "PT8M30S",
  }}
/>

Props

Property Type Description
name string Required. The name of the dish
image `string \ ImageObject \ (string \ ImageObject)[]` Required. Images of the completed dish. Google recommends multiple high-resolution images
description string A short summary describing the dish
author `string \ Person \ Organization` The creator of the recipe
datePublished string ISO 8601 date when the recipe was published
url string The canonical URL of the recipe page
prepTime string ISO 8601 duration for preparation time (e.g., "PT30M" for 30 minutes)
cookTime string ISO 8601 duration for cooking time
totalTime string ISO 8601 duration for total time (prep + cook)
recipeYield `string \ number` The quantity produced (e.g., "4 servings", "1 loaf", or just 6)
recipeCategory string The type of meal or course (e.g., "dessert", "main course")
recipeCuisine string The cuisine of the recipe (e.g., "French", "Mexican")
recipeIngredient string[] List of ingredients with quantities
recipeInstructions `string \ HowToStep \ HowToSection \ (string \ HowToStep \ HowToSection)[]` Step-by-step instructions
nutrition NutritionInformation Nutritional information per serving
aggregateRating AggregateRating The aggregate rating from users
video VideoObject A video showing how to make the recipe
keywords string Keywords about the recipe, separated by commas
scriptId string Custom ID for the script tag
scriptKey string Custom key prop for React

Duration Format (ISO 8601)

Use these formats for time durations:

  • PT15M - 15 minutes
  • PT1H - 1 hour
  • PT1H30M - 1 hour 30 minutes
  • PT2H15M - 2 hours 15 minutes

Best Practices

  1. High-quality images: Include multiple high-resolution images (16x9, 4x3, 1x1 aspect ratios)
  2. Detailed instructions: Use HowToStep objects for better structured data
  3. Complete nutrition info: Include nutrition data when possible for better search visibility
  4. Accurate times: Always provide prepTime and cookTime together
  5. Ratings: Include aggregateRating when you have user reviews
  6. Video content: Adding a video significantly improves search appearance

↑ Back to Components

OrganizationJsonLd

The OrganizationJsonLd component helps you add structured data about your organization to improve how it appears in search results and knowledge panels.

Basic Usage

import { OrganizationJsonLd } from "next-seo";

export default function AboutPage() {
  return (
    <>
      <OrganizationJsonLd
        name="Example Corporation"
        url="https://www.example.com"
        logo="https://www.example.com/logo.png"
        description="The example corporation is well-known for producing high-quality widgets"
        sameAs={[
          "https://twitter.com/example",
          "https://facebook.com/example",
          "https://linkedin.com/company/example",
        ]}
      />
      <div>
        <h1>About Example Corporation</h1>
        {/* About page content */}
      </div>
    </>
  );
}

Advanced Example with Address and Contact

<OrganizationJsonLd
  type="Organization"
  name="Example Corporation"
  url="https://www.example.com"
  logo={{
    "@type": "ImageObject",
    url: "https://www.example.com/logo.png",
    width: 600,
    height: 400,
  }}
  description="Leading provider of innovative widget solutions"
  sameAs={[
    "https://example.net/profile/example1234",
    "https://example.org/example1234",
  ]}
  address={{
    "@type": "PostalAddress",
    streetAddress: "999 W Example St Suite 99",
    addressLocality: "New York",
    addressRegion: "NY",
    postalCode: "10019",
    addressCountry: "US",
  }}
  contactPoint={{
    "@type": "ContactPoint",
    contactType: "Customer Service",
    telephone: "+1-999-999-9999",
    email: "support@example.com",
  }}
  telephone="+1-999-999-9999"
  email="contact@example.com"
  foundingDate="2010-01-01"
  vatID="FR12345678901"
  iso6523Code="0199:724500PMK2A2M1SQQ228"
  numberOfEmployees={{
    minValue: 100,
    maxValue: 999,
  }}
/>

OnlineStore Example with Return Policy

<OrganizationJsonLd
  type="OnlineStore"
  name="Example Online Store"
  url="https://www.example.com"
  logo="https://www.example.com/assets/logo.png"
  contactPoint={{
    "@type": "ContactPoint",
    contactType: "Customer Service",
    email: "support@example.com",
    telephone: "+47-99-999-9900",
  }}
  vatID="FR12345678901"
  iso6523Code="0199:724500PMK2A2M1SQQ228"
  hasMerchantReturnPolicy={{
    "@type": "MerchantReturnPolicy",
    applicableCountry: ["FR", "CH"],
    returnPolicyCountry: "FR",
    returnPolicyCategory: "https://schema.org/MerchantReturnFiniteReturnWindow",
    merchantReturnDays: 60,
    returnMethod: "https://schema.org/ReturnByMail",
    returnFees: "https://schema.org/FreeReturn",
    refundType: "https://schema.org/FullRefund",
  }}
/>

Props

Property Type Description
type `"Organization" \ "OnlineStore"` The type of organization. Defaults to "Organization"
name string The name of your organization
url string The URL of your organization's website
logo `string \ ImageObject` Your organization's logo (112x112px minimum)
description string A detailed description of your organization
sameAs `string \ string[]` URLs of your organization's profiles on other sites
address `string \ PostalAddress \ (string \ PostalAddress)[]` Physical or mailing address(es)
contactPoint `ContactPoint \ ContactPoint[]` Contact information for your organization
telephone string Primary phone number (include country code)
email string Primary email address
alternateName string Alternative name your organization goes by
foundingDate string ISO 8601 date when the organization was founded
legalName string Registered legal name if different from name
taxID string Tax ID associated with your organization
vatID string VAT code (important trust signal)
duns string Dun & Bradstreet DUNS number
leiCode string Legal Entity Identifier (ISO 17442)
naics string North American Industry Classification System code
globalLocationNumber string GS1 Global Location Number
iso6523Code string ISO 6523 identifier (e.g., "0199:724500PMK2A2M1SQQ228")
numberOfEmployees `number \ QuantitativeValue` Number of employees or range
hasMerchantReturnPolicy `MerchantReturnPolicy \ MerchantReturnPolicy[]` Return policy details (OnlineStore only)
hasMemberProgram `MemberProgram \ MemberProgram[]` Loyalty/membership program details (OnlineStore only)
scriptId string Custom ID for the script tag
scriptKey string Custom key prop for React

OnlineStore with Loyalty Program Example

<OrganizationJsonLd
  type="OnlineStore"
  name="Example Store"
  url="https://www.example.com"
  hasMemberProgram={{
    name: "Rewards Plus",
    description:
      "Earn points and unlock exclusive benefits with our loyalty program",
    url: "https://www.example.com/rewards",
    hasTiers: [
      {
        name: "Bronze",
        hasTierBenefit: "TierBenefitLoyaltyPoints",
        membershipPointsEarned: 1,
      },
      {
        name: "Silver",
        hasTierBenefit: ["TierBenefitLoyaltyPoints"],
        hasTierRequirement: {
          value: 500,
          currency: "USD",
        },
        membershipPointsEarned: 2,
      },
      {
        name: "Gold",
        hasTierBenefit: ["TierBenefitLoyaltyPoints", "TierBenefitLoyaltyPrice"],
        hasTierRequirement: {
          name: "Example Gold Credit Card",
        },
        membershipPointsEarned: 5,
        url: "https://www.example.com/rewards/gold",
      },
    ],
  }}
/>

Multiple Loyalty Programs Example

<OrganizationJsonLd
  type="OnlineStore"
  name="Premium Store"
  hasMemberProgram={[
    {
      name: "Basic Rewards",
      description: "Standard loyalty program for all customers",
      hasTiers: {
        name: "Member",
        hasTierBenefit: "TierBenefitLoyaltyPoints",
        membershipPointsEarned: 1,
      },
    },
    {
      name: "VIP Elite",
      description: "Exclusive program for premium members",
      hasTiers: [
        {
          name: "Silver VIP",
          hasTierBenefit: [
            "TierBenefitLoyaltyPoints",
            "TierBenefitLoyaltyPrice",
          ],
          hasTierRequirement: {
            value: 2500,
            currency: "USD",
          },
          membershipPointsEarned: {
            value: 10,
            unitText: "points per dollar",
          },
        },
        {
          name: "Gold VIP",
          hasTierBenefit: [
            "TierBenefitLoyaltyPoints",
            "TierBenefitLoyaltyPrice",
          ],
          hasTierRequirement: {
            price: 9.99,
            priceCurrency: "USD",
            billingDuration: 12,
            billingIncrement: 1,
            unitCode: "MON",
          },
          membershipPointsEarned: 20,
        },
      ],
    },
  ]}
/>

MemberProgram Properties

Property Type Description
name string Required. Name of the loyalty program
description string Required. Description of program benefits
url string URL where customers can sign up
hasTiers `MemberProgramTier \ MemberProgramTier[]` Required. Tier(s) of the loyalty program

MemberProgramTier Properties

Property Type Description
name string Required. Name of the tier
hasTierBenefit `string \ string[]` Required. Benefits for this tier
hasTierRequirement various (see below) Requirements to join this tier
membershipPointsEarned `number \ QuantitativeValue` Points earned per unit spent
url string URL for tier-specific signup
@id string Unique identifier for the tier

Tier Benefits

Benefits can be specified using short names or full URLs:

  • "TierBenefitLoyaltyPoints" or "https://schema.org/TierBenefitLoyaltyPoints" - Earn loyalty points
  • "TierBenefitLoyaltyPrice" or "https://schema.org/TierBenefitLoyaltyPrice" - Special member pricing

Tier Requirements

The hasTierRequirement property accepts different types based on the requirement:

Credit Card Requirement:

hasTierRequirement: {
  name: "Store Premium Credit Card";
}

Minimum Spending Requirement (MonetaryAmount):

hasTierRequirement: {
  value: 1000,
  currency: "USD"
}

Subscription Fee (UnitPriceSpecification):

hasTierRequirement: {
  price: 9.99,
  priceCurrency: "EUR",
  billingDuration: 12,      // Total duration
  billingIncrement: 1,      // Billing frequency
  unitCode: "MON"          // Unit (MON = monthly)
}

Text Description:

hasTierRequirement: "By invitation only - must maintain $10,000+ annual spending";

Membership Points Earned

Points can be specified as a simple number or as a detailed QuantitativeValue:

Simple:

membershipPointsEarned: 5;

Detailed:

membershipPointsEarned: {
  value: 10,
  minValue: 10,
  maxValue: 20,
  unitText: "points per dollar (double on special events)"
}

Best Practices

  1. Place on homepage or about page: Add this markup to your homepage or a dedicated "about us" page
  2. Use specific subtypes: Use "OnlineStore" for e-commerce sites rather than generic "Organization"
  3. Include identifiers: Add VAT ID, ISO codes, and other identifiers for better trust signals
  4. Complete address information: Provide full address details including country code
  5. Multiple locations: Use array format for addresses if you have multiple locations
  6. High-quality logo: Use a logo that looks good on white background, minimum 112x112px

↑ Back to Components

LocalBusinessJsonLd

The LocalBusinessJsonLd component helps you add structured data for local businesses to improve their appearance in Google Search and Maps results, including knowledge panels and local business carousels.

Basic Usage

import { LocalBusinessJsonLd } from "next-seo";

<LocalBusinessJsonLd
  type="Restaurant"
  name="Dave's Steak House"
  address={{
    "@type": "PostalAddress",
    streetAddress: "148 W 51st St",
    addressLocality: "New York",
    addressRegion: "NY",
    postalCode: "10019",
    addressCountry: "US",
  }}
  telephone="+12125551234"
  url="https://www.example.com"
  priceRange="$$$"
/>;

Restaurant Example with Full Details

<LocalBusinessJsonLd
  type="Restaurant"
  name="Dave's Steak House"
  address={{
    "@type": "PostalAddress",
    streetAddress: "148 W 51st St",
    addressLocality: "New York",
    addressRegion: "NY",
    postalCode: "10019",
    addressCountry: "US",
  }}
  geo={{
    "@type": "GeoCoordinates",
    latitude: 40.761293,
    longitude: -73.982294,
  }}
  url="https://www.example.com/restaurant-locations/manhattan"
  telephone="+12122459600"
  image={[
    "https://example.com/photos/1x1/photo.jpg",
    "https://example.com/photos/4x3/photo.jpg",
    "https://example.com/photos/16x9/photo.jpg",
  ]}
  servesCuisine="American"
  priceRange="$$$"
  openingHoursSpecification={[
    {
      "@type": "OpeningHoursSpecification",
      dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
      opens: "11:30",
      closes: "22:00",
    },
    {
      "@type": "OpeningHoursSpecification",
      dayOfWeek: "Saturday",
      opens: "16:00",
      closes: "23:00",
    },
    {
      "@type": "OpeningHoursSpecification",
      dayOfWeek: "Sunday",
      opens: "16:00",
      closes: "22:00",
    },
  ]}
  menu="https://www.example.com/menu"
  aggregateRating={{
    "@type": "AggregateRating",
    ratingValue: 4.5,
    ratingCount: 250,
  }}
/>

Store with Departments

<LocalBusinessJsonLd
  type="Store"
  name="Dave's Department Store"
  address={{
    "@type": "PostalAddress",
    streetAddress: "1600 Saratoga Ave",
    addressLocality: "San Jose",
    addressRegion: "CA",
    postalCode: "95129",
    addressCountry: "US",
  }}
  telephone="+14088717984"
  department={[
    {
      type: "Pharmacy",
      name: "Dave's Pharmacy",
      address: "1600 Saratoga Ave, San Jose, CA 95129",
      telephone: "+14088719385",
      openingHoursSpecification: {
        "@type": "OpeningHoursSpecification",
        dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
        opens: "09:00",
        closes: "19:00",
      },
    },
  ]}
/>

Props

Property Type Description
type `string \ string[]` Business type (e.g., "Restaurant", "Store", or ["Restaurant", "BarOrPub"])
name string Required. The name of the business
address `string \ PostalAddress \ (string \ PostalAddress)[]` Required. Physical location(s) of the business
url string The fully-qualified URL of the business location page
telephone string Primary contact phone number (include country code)
image `string \ ImageObject \ (string \ ImageObject)[]` Images of the business (multiple aspect ratios recommended)
priceRange string Relative price range (e.g., "$", "$$", "$$$", or "$10-15")
geo GeoCoordinates Geographic coordinates (min 5 decimal places precision)
openingHoursSpecification `OpeningHoursSpecification \ OpeningHoursSpecification[]` Business hours including special/seasonal hours
review `Review \ Review[]` Customer reviews (for review sites only)
aggregateRating AggregateRating Average rating based on multiple reviews
department `LocalBusinessBase \ LocalBusinessBase[]` Departments within the business
menu string URL of the menu (for food establishments)
servesCuisine `string \ string[]` Type of cuisine served (for restaurants)
sameAs `string \ string[]` URLs of business profiles on other sites
branchOf Organization Parent organization if this is a branch
currenciesAccepted string Currencies accepted (e.g., "USD")
paymentAccepted string Payment methods accepted
areaServed `string \ string[]` Geographic areas served
email string Business email address
faxNumber string Business fax number
slogan string Business slogan or tagline
description string Detailed description of the business
publicAccess boolean Whether the business location is accessible to the public
smokingAllowed boolean Whether smoking is allowed at the location
isAccessibleForFree boolean Whether access is free
scriptId string Custom ID for the script tag
scriptKey string Custom key prop for React

Opening Hours Examples

Standard Business Hours:

openingHoursSpecification={[
  {
    "@type": "OpeningHoursSpecification",
    dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
    opens: "09:00",
    closes: "17:00",
  },
  {
    "@type": "OpeningHoursSpecification",
    dayOfWeek: ["Saturday", "Sunday"],
    opens: "10:00",
    closes: "16:00",
  },
]}

24/7 Operation:

openingHoursSpecification={{
  "@type": "OpeningHoursSpecification",
  dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
  opens: "00:00",
  closes: "23:59",
}}

Closed on Specific Days:

openingHoursSpecification={{
  "@type": "OpeningHoursSpecification",
  dayOfWeek: "Sunday",
  opens: "00:00",
  closes: "00:00",
}}

Seasonal Hours:

openingHoursSpecification={{
  "@type": "OpeningHoursSpecification",
  dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
  opens: "10:00",
  closes: "18:00",
  validFrom: "2024-06-01",
  validThrough: "2024-09-30",
}}

Best Practices

  1. Use specific business types: Use the most specific LocalBusiness subtype (e.g., "Restaurant" instead of "LocalBusiness")
  2. Multiple types: For businesses that fit multiple categories, use an array (e.g., ["Restaurant", "BarOrPub"])
  3. Complete address: Provide as many address fields as possible for better local SEO
  4. High-quality images: Include multiple images with different aspect ratios (16:9, 4:3, 1:1)
  5. Accurate coordinates: Use at least 5 decimal places for latitude and longitude
  6. Opening hours: Be precise with opening hours and include seasonal variations
  7. Department naming: Include the main store name with department name (e.g., "Store Name - Pharmacy")
  8. Price range: Keep under 100 characters; use standard symbols ($, $$, $$$) or ranges

↑ Back to Components

MerchantReturnPolicyJsonLd

The MerchantReturnPolicyJsonLd component helps you add structured data for merchant return policies, enabling Google Search to display return policy information alongside your products and in knowledge panels. This component supports both detailed policy specifications and simple links to policy pages.

Basic Usage - Option A (Detailed Properties)

Use this pattern when you want to provide detailed return policy information:

import { MerchantReturnPolicyJsonLd } from "next-seo";

<MerchantReturnPolicyJsonLd
  applicableCountry={["US", "CA"]}
  returnPolicyCountry="US"
  returnPolicyCategory="https://schema.org/MerchantReturnFiniteReturnWindow"
  merchantReturnDays={30}
  returnMethod="https://schema.org/ReturnByMail"
  returnFees="https://schema.org/FreeReturn"
  refundType="https://schema.org/FullRefund"
  returnLabelSource="https://schema.org/ReturnLabelDownloadAndPrint"
/>;

Basic Usage - Option B (Link Only)

Use this pattern when you prefer to link to your return policy page:

import { MerchantReturnPolicyJsonLd } from "next-seo";

<MerchantReturnPolicyJsonLd merchantReturnLink="https://www.example.com/returns" />;

Advanced Usage with All Features

import { MerchantReturnPolicyJsonLd } from "next-seo";

<MerchantReturnPolicyJsonLd
  applicableCountry={["DE", "AT", "CH"]}
  returnPolicyCountry="IE"
  returnPolicyCategory="https://schema.org/MerchantReturnFiniteReturnWindow"
  merchantReturnDays={60}
  itemCondition={[
    "https://schema.org/NewCondition",
    "https://schema.org/DamagedCondition",
  ]}
  returnMethod={[
    "https://schema.org/ReturnByMail",
    "https://schema.org/ReturnInStore",
  ]}
  returnFees="https://schema.org/ReturnShippingFees"
  returnShippingFeesAmount={{
    value: 2.99,
    currency: "EUR",
  }}
  refundType={[
    "https://schema.org/FullRefund",
    "https://schema.org/ExchangeRefund",
  ]}
  restockingFee={{
    value: 10,
    currency: "EUR",
  }}
  returnLabelSource="https://schema.org/ReturnLabelInBox"
  // Customer remorse specific
  customerRemorseReturnFees="https://schema.org/ReturnShippingFees"
  customerRemorseReturnShippingFeesAmount={{
    value: 5.99,
    currency: "EUR",
  }}
  customerRemorseReturnLabelSource="https://schema.org/ReturnLabelDownloadAndPrint"
  // Item defect specific
  itemDefectReturnFees="https://schema.org/FreeReturn"
  itemDefectReturnLabelSource="https://schema.org/ReturnLabelInBox"
  // Seasonal override
  returnPolicySeasonalOverride={{
    startDate: "2025-12-01",
    endDate: "2025-01-05",
    returnPolicyCategory: "https://schema.org/MerchantReturnFiniteReturnWindow",
    merchantReturnDays: 30,
  }}
/>;

Product-Level Return Policy

You can also specify return policies for individual products:

import { ProductJsonLd } from "next-seo";

<ProductJsonLd
  name="Premium Wireless Headphones"
  offers={{
    price: 349.99,
    priceCurrency: "USD",
    hasMerchantReturnPolicy: {
      applicableCountry: "US",
      returnPolicyCategory:
        "https://schema.org/MerchantReturnFiniteReturnWindow",
      merchantReturnDays: 45,
      returnFees: "https://schema.org/FreeReturn",
      refundType: "https://schema.org/FullRefund",
    },
  }}
/>;

Organization-Level Return Policy

For online stores, specify a standard return policy at the organization level:

import { OrganizationJsonLd } from "next-seo";

<OrganizationJsonLd
  type="OnlineStore"
  name="Example Store"
  hasMerchantReturnPolicy={{
    applicableCountry: ["US", "CA"],
    returnPolicyCategory: "https://schema.org/MerchantReturnFiniteReturnWindow",
    merchantReturnDays: 60,
    returnFees: "https://schema.org/FreeReturn",
    refundType: "https://schema.org/FullRefund",
  }}
/>;

Props

Property Type Description
Option A Properties
applicableCountry `string \ string[]` Required (Option A). Countries where products are sold
returnPolicyCategory string Required (Option A). Type of return policy
merchantReturnDays number Days for returns (required if finite window)
returnPolicyCountry `string \ string[]` Countries where returns are processed
returnMethod `string \ string[]` How items can be returned
returnFees string Type of return fees
returnShippingFeesAmount MonetaryAmount Shipping fee for returns
refundType `string \ string[]` Types of refunds available
restockingFee `number \ MonetaryAmount` Restocking fee (percentage or fixed)
returnLabelSource string How customers get return labels
itemCondition `string \ string[]` Acceptable return conditions
Customer Remorse Properties
customerRemorseReturnFees string Fees for change-of-mind returns
customerRemorseReturnShippingFeesAmount MonetaryAmount Shipping fee for remorse returns
customerRemorseReturnLabelSource string Label source for remorse returns
Item Defect Properties
itemDefectReturnFees string Fees for defective item returns
itemDefectReturnShippingFeesAmount MonetaryAmount Shipping fee for defect returns
itemDefectReturnLabelSource string Label source for defect returns
Seasonal Override
returnPolicySeasonalOverride `SeasonalOverride \ SeasonalOverride[]` Temporary policy changes
Option B Property
merchantReturnLink string URL to return policy page
Component Properties
scriptId string Custom ID for the script tag
scriptKey string Custom key for React rendering

Return Policy Categories

  • https://schema.org/MerchantReturnFiniteReturnWindow - Limited return period
  • https://schema.org/MerchantReturnNotPermitted - No returns allowed
  • https://schema.org/MerchantReturnUnlimitedWindow - Unlimited return period

Return Methods

  • https://schema.org/ReturnByMail - Return by mail
  • https://schema.org/ReturnInStore - Return in store
  • https://schema.org/ReturnAtKiosk - Return at kiosk

Return Fees

  • https://schema.org/FreeReturn - No charge for returns
  • https://schema.org/ReturnFeesCustomerResponsibility - Customer pays for return
  • https://schema.org/ReturnShippingFees - Specific shipping fee charged

Refund Types

  • https://schema.org/FullRefund - Full monetary refund
  • https://schema.org/ExchangeRefund - Exchange for same product
  • https://schema.org/StoreCreditRefund - Store credit issued

Best Practices

  1. Choose the right option: Use Option A for detailed policies, Option B for complex or frequently changing policies
  2. Specify all countries: List all countries where your policy applies
  3. Different return scenarios: Use customer remorse and item defect properties for different conditions
  4. Seasonal variations: Use seasonal overrides for holiday return windows
  5. Product overrides: Override organization-level policies for specific products when needed
  6. Clear fee structure: Be transparent about any fees customers will incur
  7. Multiple return methods: Offer multiple return options for customer convenience
  8. Accurate time windows: Ensure merchantReturnDays matches your actual policy

↑ Back to Components

MovieCarouselJsonLd

The MovieCarouselJsonLd component helps you add structured data for movie carousels, enabling your movie lists to appear as rich results in Google Search on mobile devices. This component supports both summary page (URLs only) and all-in-one page (full movie data) patterns.

Basic Usage - Summary Page Pattern

Use this pattern when you have separate detail pages for each movie:

import { MovieCarouselJsonLd } from "next-seo";

<MovieCarouselJsonLd
  urls={[
    "https://example.com/movies/a-star-is-born",
    "https://example.com/movies/bohemian-rhapsody",
    "https://example.com/movies/black-panther",
  ]}
/>;

All-in-One Page Pattern

Use this pattern when all movie information is on a single page:

<MovieCarouselJsonLd
  movies={[
    {
      name: "A Star Is Born",
      image: "https://example.com/photos/6x9/star-is-born.jpg",
      dateCreated: "2024-10-05",
      director: "Bradley Cooper",
      review: {
        reviewRating: { ratingValue: 5 },
        author: "John D.",
      },
      aggregateRating: {
        ratingValue: 90,
        bestRating: 100,
        ratingCount: 19141,
      },
    },
    {
      name: "Bohemian Rhapsody",
      image: "https://example.com/photos/6x9/bohemian.jpg",
      dateCreated: "2024-11-02",
      director: "Bryan Singer",
      aggregateRating: {
        ratingValue: 61,
        bestRating: 100,
        ratingCount: 21985,
      },
    },
  ]}
/>

Advanced Example with All Features

<MovieCarouselJsonLd
  movies={[
    {
      name: "Black Panther",
      url: "https://example.com/movies/black-panther",
      image: [
        "https://example.com/photos/1x1/black-panther.jpg",
        "https://example.com/photos/4x3/black-panther.jpg",
        "https://example.com/photos/16x9/black-panther.jpg",
      ],
      dateCreated: "2024-02-16",
      director: {
        name: "Ryan Coogler",
        url: "https://example.com/directors/ryan-coogler",
      },
      review: {
        reviewRating: {
          ratingValue: 2,
          bestRating: 5,
        },
        author: {
          name: "Trevor R.",
          url: "https://example.com/reviewers/trevor",
        },
        reviewBody:
          "While visually stunning, the plot fell short of expectations.",
        datePublished: "2024-02-20",
      },
      aggregateRating: {
        ratingValue: 96,
        bestRating: 100,
        ratingCount: 88211,
      },
    },
  ]}
/>

Props

Property Type Description
urls `Array<string \ {url: string; position?: number}>` Required for summary pattern. URLs to individual movie pages
movies MovieListItem[] Required for all-in-one pattern. Array of movie data
scriptId string Custom ID for the script tag
scriptKey string Custom key prop for React

MovieListItem Properties

Property Type Description
name string Required. The name of the movie
image `string \ ImageObject \ (string \ ImageObject)[]` Required. Movie poster/image (6:9 aspect ratio recommended)
url string URL to the movie's page
dateCreated string Release date in ISO 8601 format
director `string \ Person` Movie director (accepts string or Person object)
review Review A review of the movie
aggregateRating AggregateRating Average rating based on multiple reviews

Best Practices

  1. Mobile-only feature: Movie carousels only appear on mobile devices in Google Search
  2. Image requirements: Use 6:9 aspect ratio images (Google's requirement for movie carousels)
  3. High-quality images: Images must be high resolution and properly formatted (.jpg, .png, .gif)
  4. Multiple images: Consider providing multiple aspect ratios for better compatibility
  5. Complete movie data: Include as many properties as possible for richer search results
  6. Consistent data: All movies in the carousel must be from the same website
  7. URL structure: For su