Next SEO
Language:
TypeScript
Stars:
8.2K
Forks:
437
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!
Have you seen the new Next.js newsletter?
Next SEO
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
Looking for v6 documentation? View Here
Still using component in Pages? View docs here [/src/pages/README.md]
🚀 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 (
Getting Started with Next SEO
{/* Your content */}
);
}
Note: For standard meta tags (
,), use Next.js's built-ingenerateMetadatafunction.
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 ☕️
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 (
My Amazing Article
{/* Article content */}
);
}
Advanced Example with Multiple Authors
Blog Posting Example
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
- Always include images: Google strongly recommends including high-resolution images with multiple aspect ratios (16x9, 4x3, 1x1)
- Use ISO 8601 dates: Include timezone information for accuracy
- Multiple authors: List all authors when applicable
- Publisher logo: Include a logo for NewsArticle type
- Update dateModified: Keep this current when updating content
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 (
Fact Check: The World is Flat
{/* Your fact check content */}
);
}
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
Best Practices
- Clear ratings: Use descriptive alternateName values that clearly indicate the verdict
- Claim summary: Keep claimReviewed concise (under 75 characters) to prevent wrapping
- Full context: Include itemReviewed when possible to provide claim origin details
- Consistent scale: Use a consistent rating scale across all your fact checks
- Author credibility: Clearly identify your fact-checking organization
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 (
Premium Article
Free preview content here...
Premium content that requires subscription...
);
}
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
Multiple Paywalled Sections
Different CreativeWork Types
// Blog with subscription content
// Comment
// Course with provider
// Review with rating
Best Practices
- Use specific types: Choose the most specific CreativeWork type (Article, NewsArticle, etc.) when applicable
- Mark paywalled sections: Use
hasPartwithcssSelectorto identify paywalled content sections - Class selectors only: Only use class selectors (e.g., ".paywall") for
cssSelector, not IDs or other selectors - Consistent selectors: Ensure your HTML classes match the
cssSelectorvalues exactly - Complete metadata: Include as much metadata as possible (author, dates, images) for better search results
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 (
Simple Chocolate Chip Cookies
{/* Recipe content */}
);
}
Advanced Example with Structured Instructions and Nutrition
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 minutesPT1H- 1 hourPT1H30M- 1 hour 30 minutesPT2H15M- 2 hours 15 minutes
Best Practices
- High-quality images: Include multiple high-resolution images (16x9, 4x3, 1x1 aspect ratios)
- Detailed instructions: Use HowToStep objects for better structured data
- Complete nutrition info: Include nutrition data when possible for better search visibility
- Accurate times: Always provide prepTime and cookTime together
- Ratings: Include aggregateRating when you have user reviews
- Video content: Adding a video significantly improves search appearance
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 (
About Example Corporation
{/* About page content */}
);
}
Advanced Example with Address and Contact
OnlineStore Example with Return Policy
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
Multiple Loyalty Programs Example
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
- Place on homepage or about page: Add this markup to your homepage or a dedicated "about us" page
- Use specific subtypes: Use "OnlineStore" for e-commerce sites rather than generic "Organization"
- Include identifiers: Add VAT ID, ISO codes, and other identifiers for better trust signals
- Complete address information: Provide full address details including country code
- Multiple locations: Use array format for addresses if you have multiple locations
- High-quality logo: Use a logo that looks good on white background, minimum 112x112px
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";
;
Restaurant Example with Full Details
Store with Departments
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
- Use specific business types: Use the most specific LocalBusiness subtype (e.g., "Restaurant" instead of "LocalBusiness")
- Multiple types: For businesses that fit multiple categories, use an array (e.g.,
["Restaurant", "BarOrPub"]) - Complete address: Provide as many address fields as possible for better local SEO
- High-quality images: Include multiple images with different aspect ratios (16:9, 4:3, 1:1)
- Accurate coordinates: Use at least 5 decimal places for latitude and longitude
- Opening hours: Be precise with opening hours and include seasonal variations
- Department naming: Include the main store name with department name (e.g., "Store Name - Pharmacy")
- Price range: Keep under 100 characters; use standard symbols ($, $$, $$$) or ranges
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";
;
Basic Usage - Option B (Link Only)
Use this pattern when you prefer to link to your return policy page:
import { MerchantReturnPolicyJsonLd } from "next-seo";
;
Advanced Usage with All Features
import { MerchantReturnPolicyJsonLd } from "next-seo";
;
Product-Level Return Policy
You can also specify return policies for individual products:
import { ProductJsonLd } from "next-seo";
;
Organization-Level Return Policy
For online stores, specify a standard return policy at the organization level:
import { OrganizationJsonLd } from "next-seo";
;
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 periodhttps://schema.org/MerchantReturnNotPermitted- No returns allowedhttps://schema.org/MerchantReturnUnlimitedWindow- Unlimited return period
Return Methods
https://schema.org/ReturnByMail- Return by mailhttps://schema.org/ReturnInStore- Return in storehttps://schema.org/ReturnAtKiosk- Return at kiosk
Return Fees
https://schema.org/FreeReturn- No charge for returnshttps://schema.org/ReturnFeesCustomerResponsibility- Customer pays for returnhttps://schema.org/ReturnShippingFees- Specific shipping fee charged
Refund Types
https://schema.org/FullRefund- Full monetary refundhttps://schema.org/ExchangeRefund- Exchange for same producthttps://schema.org/StoreCreditRefund- Store credit issued
Best Practices
- Choose the right option: Use Option A for detailed policies, Option B for complex or frequently changing policies
- Specify all countries: List all countries where your policy applies
- Different return scenarios: Use customer remorse and item defect properties for different conditions
- Seasonal variations: Use seasonal overrides for holiday return windows
- Product overrides: Override organization-level policies for specific products when needed
- Clear fee structure: Be transparent about any fees customers will incur
- Multiple return methods: Offer multiple return options for customer convenience
- Accurate time windows: Ensure merchantReturnDays matches your actual policy
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";
;
All-in-One Page Pattern
Use this pattern when all movie information is on a single page:
Advanced Example with All Features
Props
| Property | Type | Description |
|---|---|---|
urls |
Array |
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
- Mobile-only feature: Movie carousels only appear on mobile devices in Google Search
- Image requirements: Use 6:9 aspect ratio images (Google's requirement for movie carousels)
- High-quality images: Images must be high resolution and properly formatted (.jpg, .png, .gif)
- Multiple images: Consider providing multiple aspect ratios for better compatibility
- Complete movie data: Include as many properties as possible for richer search results
- Consistent data: All movies in the carousel must be from the same website
- URL structure: For summary pages, ensure all URLs point to pages on the same domain
BreadcrumbJsonLd
The BreadcrumbJsonLd component helps you add breadcrumb structured data to indicate a page's position in the site hierarchy. This can help Google display breadcrumb trails in search results, making it easier for users to understand and navigate your site structure.
Basic Usage
import { BreadcrumbJsonLd } from "next-seo";
export default function ProductPage() {
return (
Wireless Headphones XYZ
{/* Product content */}
);
}
Multiple Breadcrumb Trails
Some pages can be reached through multiple paths. You can specify multiple breadcrumb trails:
Advanced Example with Thing Objects
You can use Thing objects with @id instead of plain URL strings:
Props
| Property | Type | Description |
|---|---|---|
items |
BreadcrumbListItem[] |
Array of breadcrumb items (required if not using multipleTrails) |
multipleTrails |
BreadcrumbListItem[][] |
Array of breadcrumb trails (required if not using items) |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key prop for React |
BreadcrumbListItem Type:
| Property | Type | Description |
|---|---|---|
name |
string |
Required. The title of the breadcrumb |
item |
string \| { "@id": string } |
URL or Thing object (optional for the last breadcrumb) |
Best Practices
- Omit the last item's URL: The last breadcrumb (current page) typically shouldn't have an
itemproperty - Use logical hierarchy: Breadcrumbs should represent a typical user path, not necessarily mirror URL structure
- Keep names concise: Use clear, descriptive names that help users understand the hierarchy
- Multiple trails: Use
multipleTrailswhen a page can be logically reached through different paths - Include home: Start trails from a logical entry point (often "Home") but it's not required
- Avoid duplicates: Each trail should represent a unique path to the page
- Match visual breadcrumbs: The structured data should match the breadcrumbs shown on your page
CarouselJsonLd
The CarouselJsonLd component helps you add structured data for carousels (ItemList) to enable rich results that display multiple cards from your site in a carousel format. This component supports Course, Movie, Recipe, and Restaurant content types.
Basic Usage
Summary Page Pattern (URLs only):
import { CarouselJsonLd } from "next-seo";
// Simple array of URLs
// With custom positions
All-in-One Page Pattern (Full Data):
import { CarouselJsonLd } from "next-seo";
// Course Carousel
// Movie Carousel
// Recipe Carousel
// Restaurant Carousel
Advanced Examples
Recipe Carousel with Full Details:
Restaurant Carousel with Opening Hours:
Props
| Property | Type | Description |
|---|---|---|
urls |
SummaryPageItem[] |
Array of URLs for summary page pattern |
contentType |
"Course" \| "Movie" \| "Recipe" \| "Restaurant" |
Type of content in the carousel (for all-in-one) |
items |
CourseItem[] \| MovieItem[] \| RecipeItem[] \| RestaurantItem[] |
Array of items matching the content type |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key prop for React |
SummaryPageItem Type:
| Type | Description |
|---|---|
string |
Simple URL string |
{ url: string; position?: number } |
URL with optional custom position |
Best Practices
-
Choose the right pattern:
- Use summary page pattern when you have separate detail pages for each item
- Use all-in-one pattern when all content is on a single page
-
Consistent content types: All items in a carousel must be of the same type (e.g., all recipes or all movies)
-
Required images:
- Movies require at least one image
- Recipes should include images for better visibility
- Use multiple aspect ratios when possible
-
Position numbering:
- Positions start at 1, not 0
- If not specified, positions are auto-assigned sequentially
-
URL structure: For summary pages, ensure all URLs point to pages on the same domain
-
Rich content: Include as much relevant information as possible for better search results
-
Validation: Test your structured data with Google's Rich Results Test
CourseJsonLd
The CourseJsonLd component helps you add structured data for courses to enable course list rich results in Google Search. This can help prospective students discover your courses more easily.
Basic Usage
Single Course:
import { CourseJsonLd } from "next-seo";
;
Course List:
import { CourseJsonLd } from "next-seo";
// Summary page pattern - just URLs
// All-in-one page pattern - full course data
Props
Single Course Props:
| Property | Type | Description |
|---|---|---|
type |
"single" |
Optional. Explicitly sets single course pattern |
name |
string |
Required. The title of the course |
description |
string |
Required. A description of the course (60 char limit for display) |
url |
string |
The URL of the course page |
provider |
string \| Organization \| Omit |
The organization offering the course |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key for React reconciliation |
Course List Props:
| Property | Type | Description |
|---|---|---|
type |
"list" |
Required. Sets the course list pattern |
urls |
(string \| { url: string; position?: number })[] |
URLs for summary page pattern |
courses |
CourseListItem[] |
Full course data for all-in-one pattern |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key for React reconciliation |
Advanced Example
import { CourseJsonLd } from "next-seo";
export default function CourseCatalogPage() {
return (
Our Course Catalog
{/* Your course list UI */}
);
}
Best Practices
- Minimum of 3 courses: Google requires at least 3 courses for course list rich results
- Consistent provider: Use the same format for provider across all courses
- Description length: Keep descriptions under 60 characters for optimal display
- Valid URLs: Ensure all course URLs are accessible and on the same domain
- Choose the right pattern:
- Use summary page pattern when courses have their own detail pages
- Use all-in-one pattern when all course information is on a single page
- Avoid promotional content: Don't include prices, discounts, or marketing language in course names
EventJsonLd
The EventJsonLd component helps you add structured data for events to improve their discoverability in Google Search results and other Google products like Google Maps. Events can appear with rich features including images, dates, locations, and ticket information.
Basic Usage
import { EventJsonLd } from "next-seo";
;
Standard Event Example
Event Status Examples
Cancelled Event
Rescheduled Event
Props
| Property | Type | Description |
|---|---|---|
name |
string |
Required. The full title of the event |
startDate |
string |
Required. Start date/time in ISO-8601 format |
location |
string \| Place |
Required. Event venue (string or Place object) |
endDate |
string |
End date/time in ISO-8601 format |
description |
string |
Detailed description of the event |
eventStatus |
EventStatusType |
Status: EventScheduled (default), EventCancelled, EventPostponed, EventRescheduled |
image |
string \| ImageObject \| (string \| ImageObject)[] |
Event images (recommended: multiple aspect ratios) |
offers |
Offer \| Offer[] |
Ticket/pricing information |
performer |
string \| Person \| PerformingGroup \| array |
Performers at the event |
organizer |
string \| Person \| Organization |
Event host/organizer |
previousStartDate |
string \| string[] |
Previous date(s) for rescheduled events |
url |
string |
URL of the event page |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key prop for React |
Offer Type
| Property | Type | Description |
|---|---|---|
url |
string |
URL to purchase tickets |
price |
number |
Lowest available price (use 0 for free events) |
priceCurrency |
string |
3-letter ISO 4217 currency code (e.g., "USD") |
availability |
string |
Availability status (InStock, SoldOut, PreOrder) |
validFrom |
string |
Date/time when tickets go on sale |
Best Practices
- Date/Time Format: Always use ISO-8601 format with timezone offset (e.g.,
2025-07-21T19:00-05:00) - Day-long Events: For all-day events, use date only format (e.g.,
2025-07-04) - Location Details: Provide complete address information for better discoverability
- Multiple Images: Include images in different aspect ratios (16:9, 4:3, 1:1) for various display contexts
- Event Status: Keep original dates when cancelling/postponing; only update the
eventStatus - Free Events: Set
price: 0for events without charge - Multiple Performers: Use an array when listing multiple artists or speakers
- Rescheduled Events: Always include
previousStartDatewhen usingEventRescheduledstatus
Date and Time Guidelines
- Include timezone: Specify UTC/GMT offset (e.g.,
-05:00for EST) - Multi-day events: Set both
startDateandendDate - Unknown end time: Omit
endDaterather than guessing - Date-only format: Use for all-day events (e.g., festivals)
Example timezone handling:
// New York event during standard time
startDate: "2025-12-21T19:00:00-05:00";
// California event during daylight saving time
startDate: "2025-07-21T19:00:00-07:00";
// All-day event
startDate: "2025-07-04";
endDate: "2025-07-04";
FAQJsonLd
The FAQJsonLd component helps you add structured data for frequently asked questions (FAQ) pages. This can help your FAQ content appear as rich results in Google Search, making it easier for users to find answers to common questions.
Note: FAQ rich results are only available for well-known, authoritative government or health websites. However, implementing proper FAQ structured data is still valuable for SEO and can help search engines better understand your content.
Basic Usage
import { FAQJsonLd } from "next-seo";
export default function FAQPage() {
return (
Frequently Asked Questions
{/* Your FAQ content */}
);
}
Advanced Example with HTML Content
FAQ answers support HTML content including links, lists, and formatting:
**Note**: You must include `contentUrl` and at least one of: `creator`, `creditText`, `copyrightNotice`, or `license` for the image to be eligible for enhancements like the Licensable badge.
#### Best Practices
1. **Always provide licensing information**: Include the `license` property to make your images eligible for the Licensable badge
2. **Credit creators properly**: Use structured creator information to ensure proper attribution
3. **Include acquire license page**: Help users understand how they can legally use your images
4. **Use consistent copyright notices**: Maintain clear copyright information across your images
5. **Multiple creators**: When multiple people contributed to an image, list all creators
6. **Organization vs Person**: Use Organization type for companies/studios, Person type for individuals
### QuizJsonLd
The `QuizJsonLd` component helps you add structured data for educational quizzes and flashcards. This can help your educational content appear in Google's education Q&A carousel when users search for educational topics.
#### Basic Usage
```tsx
import { QuizJsonLd } from "next-seo";
export default function BiologyQuizPage() {
return (
{/* Your quiz content */}
);
}
Props
| Property | Type | Description |
|---|---|---|
questions |
QuestionInput[] |
Required. Array of flashcard questions and answers |
about |
string \| Thing |
The subject or topic of the quiz |
educationalAlignment |
Array |
Educational alignments specifying subject and/or grade level |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key for React (defaults to "quiz-jsonld") |
Question Formats
The questions array accepts several formats:
-
Simple object (recommended):
{ question: "What is 2 + 2?", answer: "4" } -
String format (for fact-based flashcards):
"The Earth revolves around the Sun in 365.25 days"; -
Text/acceptedAnswer format:
{ text: "What is DNA?", acceptedAnswer: "Deoxyribonucleic acid" } -
Full Answer object:
{ text: "Explain photosynthesis", acceptedAnswer: { "@type": "Answer", text: "The process by which plants convert light energy into chemical energy" } }
Advanced Example
Best Practices
- Educational content only: Quiz structured data is specifically for educational flashcards and Q&A
- Use "Flashcard" type: All questions automatically use
eduQuestionType: "Flashcard"as required by Google - Clear answers: Provide concise, factual answers appropriate for the educational level
- Subject alignment: Always specify the educational subject using
educationalAlignment - Grade level: Include the target grade or educational level when applicable
- Match visible content: The structured data should match the quiz content displayed on your page
- Single answer format: Each question should have one clear, authoritative answer
Note: The education Q&A carousel is available when searching for education-related topics in English, Portuguese, Spanish (Mexico), and Vietnamese.
DatasetJsonLd
The DatasetJsonLd component helps you add structured data for datasets, making them easier to find in Google's Dataset Search. This is ideal for scientific data, government data, machine learning datasets, and any other structured data collections.
Basic Usage
import { DatasetJsonLd } from "next-seo";
export default function DatasetPage() {
return (
{/* Your dataset page content */}
);
}
Advanced Example with Full Features
Props
| Property | Type | Description |
|---|---|---|
name |
string |
Required. A descriptive name of the dataset |
description |
string |
Required. A short summary describing the dataset (50-5000 characters) |
url |
string |
URL of the dataset landing page |
sameAs |
string \| string[] |
URLs of pages that unambiguously indicate the dataset's identity |
identifier |
string \| PropertyValue \| (string \| PropertyValue)[] |
Identifiers such as DOI or Compact Identifiers |
keywords |
string \| string[] |
Keywords summarizing the dataset |
license |
string \| CreativeWork |
License under which the dataset is distributed |
isAccessibleForFree |
boolean |
Whether the dataset is accessible without payment |
hasPart |
Dataset \| Dataset[] |
Smaller datasets that are part of this dataset |
isPartOf |
string \| Dataset |
A larger dataset that this dataset is part of |
creator |
string \| Person \| Organization \| (string \| Person \| Organization)[] |
The creator or author of the dataset |
funder |
string \| Person \| Organization \| (string \| Person \| Organization)[] |
Person or organization that provides financial support |
includedInDataCatalog |
DataCatalog |
The catalog to which the dataset belongs |
distribution |
DataDownload \| DataDownload[] |
Download locations and formats for the dataset |
temporalCoverage |
string |
Time interval covered by the dataset (ISO 8601 format) |
spatialCoverage |
string \| Place |
Spatial aspect of the dataset (location name or coordinates) |
alternateName |
string \| string[] |
Alternative names for the dataset |
citation |
string \| CreativeWork \| (string \| CreativeWork)[] |
Academic articles to cite alongside the dataset |
measurementTechnique |
string \| string[] |
Technique or methodology used in the dataset |
variableMeasured |
string \| PropertyValue \| (string \| PropertyValue)[] |
Variables that the dataset measures |
version |
string \| number |
Version number for the dataset |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key for React (defaults to "dataset-jsonld") |
Spatial Coverage Examples
// Named location
spatialCoverage="United States"
// Point coordinates
spatialCoverage={{
geo: {
latitude: 39.3280,
longitude: 120.1633,
}
}}
// Bounding box (format: "minLat minLon maxLat maxLon")
spatialCoverage={{
geo: {
box: "39.3280 120.1633 40.445 123.7878",
}
}}
// Circle (format: "latitude longitude radius")
spatialCoverage={{
geo: {
circle: "39.3280 120.1633 100",
}
}}
Temporal Coverage Examples
// Single date
temporalCoverage = "2024";
// Date range
temporalCoverage = "2020-01-01/2024-12-31";
// Open-ended range
temporalCoverage = "2024-01-01/..";
Best Practices
- Comprehensive descriptions: Provide detailed descriptions (50-5000 characters) that clearly explain what the dataset contains
- Use persistent identifiers: Include DOIs or other persistent identifiers when available
- Multiple formats: If your dataset is available in multiple formats, list all distributions
- Specify license: Always include license information to clarify usage rights
- Include temporal/spatial coverage: Help users understand the scope of your data
- Use ORCID/ROR IDs: When specifying creators or funders, use ORCID IDs for individuals and ROR IDs for organizations in the
sameAsfield - Version your datasets: Include version numbers to help users track updates
- Link to catalogs: If your dataset is in a repository like data.gov, include the
includedInDataCatalogproperty
Note: Dataset structured data helps your datasets appear in Google's Dataset Search, which is specifically designed for discovering research and government data.
JobPostingJsonLd
The JobPostingJsonLd component helps you add structured data for job postings to improve their appearance in Google's job search results and the Google Jobs experience.
Basic Usage
import { JobPostingJsonLd } from "next-seo";
export default function JobPage() {
return (
Software Engineer
{/* Job posting content */}
);
}
Advanced Example with Full Details
Remote Job Example
Hybrid Job Example (Remote + Office)
Props
| Property | Type | Description |
|---|---|---|
title |
string |
Required. The title of the job (not the posting). E.g., "Software Engineer" |
description |
string |
Required. The full job description in HTML format |
datePosted |
string |
Required. ISO 8601 date when the job was posted |
hiringOrganization |
string \| Organization |
Required. The organization offering the job |
jobLocation |
string \| Place \| (string \| Place)[] |
Physical location(s) where employee reports to work |
url |
string |
The canonical URL for the job posting |
validThrough |
string |
ISO 8601 date when the job posting expires |
employmentType |
EmploymentType \| EmploymentType[] |
Type of employment (FULL_TIME, PART_TIME, CONTRACTOR, etc.) |
identifier |
string \| PropertyValue |
The hiring organization's unique identifier for the job |
baseSalary |
MonetaryAmount |
The base salary of the job (as provided by employer) |
applicantLocationRequirements |
Country \| State \| (Country \| State)[] |
Geographic locations where employees may be located for remote jobs |
jobLocationType |
"TELECOMMUTE" |
Set to "TELECOMMUTE" for 100% remote jobs |
directApply |
boolean |
Whether the URL enables direct application |
educationRequirements |
string \| EducationalOccupationalCredential \| (string \| EducationalOccupationalCredential)[] |
Education requirements for the position |
experienceRequirements |
string \| OccupationalExperienceRequirements |
Experience requirements for the position |
experienceInPlaceOfEducation |
boolean |
Whether experience can substitute for education requirements |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key for React (defaults to "jobposting-jsonld") |
Employment Type Values
Use these values for the employmentType property:
FULL_TIME- Full-time employmentPART_TIME- Part-time employmentCONTRACTOR- Contractor positionTEMPORARY- Temporary employmentINTERN- Internship positionVOLUNTEER- Volunteer positionPER_DIEM- Paid by the dayOTHER- Other employment type
Salary Examples
// Hourly wage
baseSalary={{
currency: "USD",
value: {
value: 25.00,
unitText: "HOUR",
},
}}
// Annual salary range
baseSalary={{
currency: "USD",
value: {
minValue: 80000,
maxValue: 120000,
unitText: "YEAR",
},
}}
// Monthly salary
baseSalary={{
currency: "EUR",
value: {
value: 5000,
unitText: "MONTH",
},
}}
Best Practices
- Complete job descriptions: Use HTML formatting with
,, and `` tags for better structure - Include salary information: Jobs with salary info get more visibility and engagement
- Set expiration dates: Always include
validThroughto automatically expire old postings - Use employment type: Specify whether the job is full-time, part-time, contract, etc.
- Remote job requirements: For remote jobs, always specify
applicantLocationRequirements - Direct apply: Set
directApply: trueif users can apply directly on your site - Multiple locations: List all office locations if the job can be performed at multiple sites
- Remove expired jobs: Update or remove the structured data when jobs are filled
Note: Job postings must comply with Google's content policies. Jobs must be actual openings (not recruiting firms collecting resumes), include application instructions, and be removed when filled.
DiscussionForumPostingJsonLd
The DiscussionForumPostingJsonLd component helps you add structured data for forum posts and discussions to improve their appearance in Google's Discussions and Forums search feature.
Basic Usage
import { DiscussionForumPostingJsonLd } from "next-seo";
;
Props
| Property | Type | Description |
|---|---|---|
type |
"DiscussionForumPosting" \| "SocialMediaPosting" |
The type of posting. Defaults to "DiscussionForumPosting" |
author |
string \| Person \| Organization \| Author[] |
Required. The author(s) of the post |
datePublished |
string |
Required. Publication date in ISO 8601 format |
text |
string |
The text content of the post |
image |
string \| ImageObject \| (string \| ImageObject)[] |
Images in the post |
video |
VideoObject |
Video content in the post |
headline |
string |
The title of the post |
url |
string |
The canonical URL of the discussion |
dateModified |
string |
Last modification date in ISO 8601 format |
comment |
Comment[] |
Comments/replies to the post |
creativeWorkStatus |
string |
Status of the post (e.g., "Deleted") |
interactionStatistic |
InteractionCounter \| InteractionCounter[] |
User interaction statistics |
isPartOf |
string \| CreativeWork |
The forum/subforum this post belongs to |
sharedContent |
string \| WebPage \| ImageObject \| VideoObject |
Content shared in the post |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
React key for the script tag |
Nested Comments Example
Social Media Posting Example
Interaction Types
The following interaction types are supported for interactionStatistic:
https://schema.org/LikeAction- Likes or upvoteshttps://schema.org/DislikeAction- Dislikes or downvoteshttps://schema.org/ViewAction- View counthttps://schema.org/CommentActionorhttps://schema.org/ReplyAction- Comment counthttps://schema.org/ShareAction- Share count
Best Practices
- Include all visible content: Add all text, images, and videos that appear in the post
- Nested comments: Use the nested structure to represent threaded discussions accurately
- Author information: Include author URLs linking to profile pages when available
- Interaction statistics: Add engagement metrics to help Google understand post popularity
- Deleted content: Use
creativeWorkStatus: "Deleted"for removed posts that remain for context - Forum hierarchy: Use
isPartOfto indicate which subforum or category the post belongs to - ISO 8601 dates: Always use proper date formatting with timezone information
- Multi-page threads: For paginated discussions, set the
urlto the first page
Note: DiscussionForumPosting is designed for forum-style sites where people share first-hand perspectives. For Q&A formats, use Q&A structured data instead.
EmployerAggregateRatingJsonLd
The EmployerAggregateRatingJsonLd component helps you add structured data for user-generated ratings about hiring organizations. This enables job seekers to see ratings in the enriched job search experience on Google.
Basic Usage
import { EmployerAggregateRatingJsonLd } from "next-seo";
;
Props
| Property | Type | Description |
|---|---|---|
itemReviewed |
string \| Organization |
Required. The organization being rated |
ratingValue |
number \| string |
Required. The rating value (number, fraction, or percentage) |
ratingCount |
number |
The total number of ratings (at least one of ratingCount or reviewCount required) |
reviewCount |
number |
The number of reviews (at least one of ratingCount or reviewCount required) |
bestRating |
number |
The highest value allowed in this rating system (default: 5) |
worstRating |
number |
The lowest value allowed in this rating system (default: 1) |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
React key for the script tag |
Advanced Example
Custom Rating Scale Example
Best Practices
- Always include organization details: Provide as much information about the organization as possible
- Use sameAs property: Link to the organization's official website or social media profiles
- Rating scales: If not using a 5-point scale, always specify bestRating and worstRating
- Count accuracy: Ensure ratingCount and reviewCount reflect actual user ratings on your site
- Rating derivation: The ratingValue must be accurately calculated from user ratings
Note: At least one of
ratingCountorreviewCountmust be provided. The component will throw an error if neither is present.
Looking for job posting structured data? Check out JobPostingJsonLd to add complete job listing structured data alongside employer ratings.
VacationRentalJsonLd
The VacationRentalJsonLd component helps you add structured data for vacation rental listings to improve their appearance in Google Search results. Users can see listing information such as name, description, images, location, rating, and reviews directly in search results.
Basic Usage
import { VacationRentalJsonLd } from "next-seo";
;
Advanced Usage
Props
| Property | Type | Description |
|---|---|---|
| containsPlace | Accommodation |
Required. Details about the accommodation including occupancy |
| containsPlace.occupancy | QuantitativeValue |
Required. Maximum number of guests |
| containsPlace.occupancy.value | number |
Required. The numerical value of guests |
| identifier | string |
Required. A unique identifier for the property |
| image | string \| ImageObject \| array |
Required. Minimum 8 photos (bedroom, bathroom, common area) |
| latitude | number \| string |
Required. Latitude with 5 decimal precision |
| longitude | number \| string |
Required. Longitude with 5 decimal precision |
| name | string |
Required. The name of the vacation rental |
additionalType |
string |
Type of rental (e.g., House, Villa, Apartment, Cottage) |
address |
PostalAddress |
Full physical address of the rental |
aggregateRating |
AggregateRating |
Average rating based on multiple reviews |
brand |
Brand |
The brand associated with the property |
checkinTime |
string |
Earliest check-in time in ISO 8601 format |
checkoutTime |
string |
Latest check-out time in ISO 8601 format |
description |
string |
A description of the property |
knowsLanguage |
string \| string[] |
Languages the host speaks (IETF BCP 47) |
review |
Review \| Review[] |
User reviews of the listing |
geo |
object |
Alternative way to specify coordinates |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom data-seo attribute value |
Accommodation Properties
| Property | Type | Description |
|---|---|---|
additionalType |
string |
Type of room (EntirePlace, PrivateRoom, SharedRoom) |
bed |
BedDetails \| BedDetails[] |
Information about beds |
amenityFeature |
LocationFeatureSpecification \| array |
Property amenities |
floorSize |
QuantitativeValue |
Size with unitCode (FTK/SQFT for sq ft, MTK/SQM for sq m) |
numberOfBathroomsTotal |
number |
Total bathrooms (can be decimal, e.g., 2.5) |
numberOfBedrooms |
number |
Total number of bedrooms |
numberOfRooms |
number |
Total number of rooms |
petsAllowed |
boolean |
Whether pets are allowed |
smokingAllowed |
boolean |
Whether smoking is allowed |
Amenity Feature Values
Boolean amenities (use value: true/false):
ac,airportShuttle,balcony,beachAccess,childFriendly,crib,elevator,fireplace,freeBreakfast,gymFitnessEquipment,heating,hotTub,instantBookable,ironingBoard,kitchen,microwave,outdoorGrill,ovenStove,patio,petsAllowed,pool,privateBeachAccess,selfCheckinCheckout,smokingAllowed,tv,washerDryer,wheelchairAccessible,wifi
Non-boolean amenities (use value: "string"):
internetType: "Free", "Paid", "None"parkingType: "Free", "Paid", "None"poolType: "Indoor", "Outdoor", "None"licenseNum: License number with authority context
Best Practices
- Minimum 8 images: Include at least one photo of bedroom, bathroom, and common areas
- Precise coordinates: Use at least 5 decimal places for latitude/longitude
- Complete address: Provide full physical address including unit numbers
- Accurate occupancy: Specify the maximum number of guests allowed
- Languages: List all languages the host can communicate in
- Reviews: Include the
contentReferenceTimefor French listings - Unique identifier: Use a stable ID that won't change with content updates
Note: This feature requires integration with Google's Hotel Center and is limited to sites that meet eligibility criteria. Visit the vacation rental interest form to get started.
VideoJsonLd
The VideoJsonLd component helps you add structured data for videos to improve their appearance in Google Search results. This includes standard video results, video carousels, and rich video previews. You can also mark live videos with a LIVE badge, add key moments for video navigation, and specify viewing restrictions.
Basic Usage
import { VideoJsonLd } from "next-seo";
;
Advanced Usage with All Features
Live Video with LIVE Badge
Video with Key Moments (Clips)
Video with Automatic Key Moments (SeekToAction)
Props
| Property | Type | Description |
|---|---|---|
name |
string |
Required. The title of the video |
description |
string |
Required. A description of the video |
thumbnailUrl |
string \| ImageObject \| array |
Required. URLs or ImageObjects for video thumbnails. Google recommends multiple aspect ratios |
uploadDate |
string |
Required. The date and time the video was published in ISO 8601 format |
contentUrl |
string |
Direct URL to the video file. Recommended if available |
embedUrl |
string |
URL to the embedded video player. Use if contentUrl isn't available |
duration |
string |
Video duration in ISO 8601 format (e.g., "PT30M" for 30 minutes) |
expires |
string |
Date after which the video is no longer available |
interactionStatistic |
InteractionCounter \| array |
View counts, likes, or other interaction metrics |
regionsAllowed |
string \| string[] |
Countries where the video is viewable (ISO 3166 format) |
ineligibleRegion |
string \| string[] |
Countries where the video is blocked |
publication |
BroadcastEvent \| array |
For live videos - includes broadcast times and live status |
hasPart |
Clip \| Clip[] |
Video segments/chapters with timestamps and labels |
potentialAction |
SeekToAction |
URL pattern for automatic key moments |
author |
string \| Person \| Organization \| array |
Video creator(s) |
publisher |
Organization |
Organization that published the video |
type |
"VideoObject" |
Schema type. Defaults to "VideoObject" |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key for React |
Best Practices
- Thumbnail Images: Provide multiple thumbnail URLs in different aspect ratios (16:9, 4:3, 1:1) for optimal display
- Duration Format: Use ISO 8601 duration format: PT[hours]H[minutes]M[seconds]S
- Content vs Embed URL:
- Use
contentUrlfor direct video files (mp4, webm, etc.) - Use
embedUrlfor video player pages - Provide both when possible
- Use
- Live Videos: For live streams, always include
publicationwithisLiveBroadcast: true - Key Moments:
- Use
hasPartwithClipobjects when you want to specify exact timestamps - Use
potentialActionwithSeekToActionto let Google automatically detect key moments
- Use
- Timestamps: Always use ISO 8601 format with timezone information
- Region Restrictions: Use two-letter ISO 3166-1 country codes
ProfilePageJsonLd
The ProfilePageJsonLd component helps you add structured data for profile pages where creators (either people or organizations) share first-hand perspectives. This helps Google Search understand the creators in an online community and show better content from that community in search results, including the Discussions and Forums feature.
Basic Usage
import { ProfilePageJsonLd } from "next-seo";
;
Advanced Usage
Organization Profile Example
Props
| Property | Type | Description |
|---|---|---|
mainEntity |
string \| Person \| Organization \| Omit \| Omit |
Required. The person or organization this profile page is about |
dateCreated |
string |
Date and time the profile was created (ISO 8601 format) |
dateModified |
string |
Date and time the profile was last modified (ISO 8601 format) |
scriptId |
string |
Custom ID for the script tag |
scriptKey |
string |
Custom key for React reconciliation |
Person/Organization Properties
When providing an object for mainEntity, you can include these properties:
Common Properties:
name: The primary name (real name preferred)alternateName: Alternate identifier (e.g., username)identifier: Unique ID within your sitedescription: User's byline or credentialimage: Profile image URLsameAs: Array of external profile URLsinteractionStatistic: User statistics (followers, likes, etc.)agentInteractionStatistic: User's own activity statistics
Interaction Types:
https://schema.org/FollowAction: Number of followers/followinghttps://schema.org/LikeAction: Number of likeshttps://schema.org/WriteAction: Number of postshttps://schema.org/ShareAction: Number of reshareshttps://schema.org/BefriendAction: Bi-directional relationships
Best Practices
- Profile focus: The page must primarily focus on a single person or organization
- Real names: Use
namefor real names andalternateNamefor usernames - Stable identifiers: Use IDs that won't change even if usernames change
- Multiple images: Include profile images in multiple aspect ratios (16x9, 4x3, 1x1)
- ISO 8601 dates: Always include timezone information in dates
- Platform statistics: Only include stats from the current platform
Valid Use Cases
✅ User profile pages on forums or social media sites ✅ Author pages on news sites ✅ "About Me" pages on blog sites ✅ Employee pages on company websites
Invalid Use Cases
❌ Main home page of a store ❌ Organization review sites (where the org isn't affiliated with the site)
Note: ProfilePage markup is designed for sites where creators share first-hand perspectives. It can be linked from Article and Recipe structured data authors, and is often used in discussion forum and Q&A page structured data.
SoftwareApplicationJsonLd
The SoftwareApplicationJsonLd component helps you add structured data for software applications, including mobile apps, web apps, desktop software, and games. This can help your app appear in rich results and improve its visibility in app-related searches.
Basic Usage (Free App)
import { SoftwareApplicationJsonLd } from "next-seo";
;
Paid App Example
Mobile Application
Web Application
Video Game (Co-typed)
For video games, Google requires co-typing with another application type:
Props
| Property | Type | Description |
|---|---|---|
name |
string |
Required. The name of the software application |
type |
ApplicationType \| VideoGameCoTyped |
Type of application. Defaults to "SoftwareApplication" |
offers |
Offer \| Offer[] |
Required. Pricing information. Set price to 0 for free apps |
aggregateRating |
AggregateRating |
Required (or use review). Average rating information |
review |
Review \| Review[] |
Required (or use aggregateRating). Individual reviews |
applicationCategory |
string |
Recommended. Category of the app (e.g., "GameApplication") |
operatingSystem |
string |
Recommended. Required OS (e.g., "Windows 10, macOS 10.15+") |
description |
string |
Description of the application |
url |
string |
URL of the app's webpage |
image |
string \| ImageObject \| (string \| ImageObject)[] |
App icon or logo |
screenshot |
string \| ImageObject \| (string \| ImageObject)[] |
Screenshots of the app |
featureList |
string \| string[] |
Key features of the app |
permissions |
string \| string[] |
Required permissions |
softwareVersion |
string |
Current version number |
datePublished |
string |
Initial release date |
dateModified |
string |
Last update date |
author |
string \| Person \| Organization |
Developer or development team |
publisher |
Organization |
Publishing organization |
downloadUrl |
string |
Direct download link |
installUrl |
string |
Installation link |
memoryRequirements |
string |
RAM requirements |
storageRequirements |
string |
Storage space needed |
processorRequirements |
string |
CPU requirements |
countriesSupported |
string \| string[] |
Supported countries |
applicationSuite |
string |
Suite the app belongs to |
Application Types
The component supports all Google-recognized application types:
SoftwareApplication(default)MobileApplicationWebApplicationGameApplicationSocialNetworkingApplicationTravelApplicationShoppingApplicationSportsApplicationLifestyleApplicationBusinessApplicationDesignApplicationDeveloperApplicationDriverApplicationEducationalApplicationHealthApplicationFinanceApplicationSecurityApplicationBrowserApplicationCommunicationApplicationDesktopEnhancementApplicationEntertainmentApplicationMultimediaApplicationHomeApplicationUtilitiesApplicationReferenceApplication
Best Practices
- Always include pricing: Use
offerswithprice: 0for free apps - Provide ratings or reviews: Include either
aggregateRatingorreview(required by Google) - Specify OS requirements: Use
operatingSystemfor better user experience - Multiple screenshots: Include various screenshots showing key features
- Video games: Always co-type with another application type (e.g.,
["VideoGame", "MobileApplication"]) - Feature lists: Highlight key features that differentiate your app
- Version information: Keep
softwareVersionanddateModifiedcurrent - Permissions transparency: List all required permissions for mobile apps
ProductJsonLd
The ProductJsonLd component helps you add structured data for products to improve their appearance in search results. Products can appear as rich snippets with ratings, prices, and availability information.
Basic Usage
import { ProductJsonLd } from "next-seo";
;
Product with Reviews
Product with Pros and Cons
Shopping Aggregator (Multiple Sellers)
Complete Example with All Features
Props
| Property | Type | Description |
|---|---|---|
name |
string |
Required. Product name |
description |
string |
Product description |
image |
string \| ImageObject \| Array |
Product images |
sku |
string |
Stock Keeping Unit |
mpn |
string |
Manufacturer Part Number |
gtin |
string |
Global Trade Item Number |
gtin8 |
string |
8-digit GTIN |
gtin12 |
string |
12-digit GTIN (UPC) |
gtin13 |
string |
13-digit GTIN (EAN) |
gtin14 |
string |
14-digit GTIN |
brand |
string \| Brand |
Product brand |
review |
ProductReview \| ProductReview[] |
Product reviews |
aggregateRating |
AggregateRating |
Aggregate rating from all reviews |
offers |
ProductOffer \| AggregateOffer \| ProductOffer[] |
Price and availability (recommended) |
category |
string |
Product category |
color |
string |
Product color |
material |
string |
Product material |
model |
string |
Product model |
productID |
string |
Product identifier |
url |
string |
Product page URL |
weight |
string \| QuantitativeValue |
Product weight |
width |
string \| QuantitativeValue |
Product width |
height |
string \| QuantitativeValue |
Product height |
depth |
string \| QuantitativeValue |
Product depth |
additionalProperty |
PropertyValue[] |
Additional product properties |
manufacturer |
string \| Organization \| Person |
Product manufacturer |
releaseDate |
string |
Product release date |
productionDate |
string |
Production date |
purchaseDate |
string |
Purchase date |
expirationDate |
string |
Expiration date |
award |
string \| string[] |
Awards received |
isCar |
boolean |
Set to true for car products |
Important Requirements
Google requires at least one of the following properties for product snippets:
review- A nested review of the productaggregateRating- The overall rating based on multiple reviewsoffers- Price and availability information
Offer Properties
| Property | Type | Description |
|---|---|---|
price |
number \| string |
Product price |
priceCurrency |
string |
Currency code (e.g., "USD") |
availability |
ItemAvailability |
Availability status |
priceValidUntil |
string |
Date until price is valid |
url |
string |
URL to purchase product |
seller |
Organization \| Person |
Seller information |
itemCondition |
string |
Condition (New, Used, Refurbished, etc.) |
AggregateOffer Properties (Multiple Sellers)
| Property | Type | Description |
|---|---|---|
lowPrice |
number \| string |
Required. Lowest price |
priceCurrency |
string |
Required. Currency code |
highPrice |
number \| string |
Highest price |
offerCount |
number |
Number of offers |
Best Practices
- Always include one of: review, aggregateRating, or offers (Google requirement)
- Multiple images: Provide images in different aspect ratios (1x1, 4x3, 16x9)
- Use specific identifiers: Include SKU, MPN, or GTIN when available
- Pros and cons: Use positiveNotes and negativeNotes for editorial reviews
- Price information: Always include priceCurrency with price
- Availability: Use schema.org values (InStock, OutOfStock, PreOrder, etc.)
- Multiple sellers: Use AggregateOffer for shopping comparison sites
- Car products: Set
isCar={true}for automotive products to add Car type
ProductGroup (Product Variants)
The ProductJsonLd component now supports ProductGroup for representing product variants (different sizes, colors, materials, etc.) of the same product. This helps Google understand product variations and can enable variant displays in search results.
Single-Page Variant Example
Use this approach when all variants are selectable on a single product page:
import { ProductJsonLd } from "next-seo";
;
Multi-Page Variant Example
Use this approach when each variant has its own page:
// On a specific variant page
ProductGroup Properties
| Property | Type | Description |
|---|---|---|
type |
"ProductGroup" |
Specifies ProductGroup type |
productGroupID |
string |
Required. Parent SKU or group identifier |
variesBy |
string \| string[] |
Properties that vary (size, color, material, etc.) |
hasVariant |
Array |
Array of product variants |
audience |
PeopleAudience |
Target audience (age, gender) |
Variant Properties
When defining variants in hasVariant, you can include:
| Property | Type | Description |
|---|---|---|
name |
string |
Variant-specific name |
sku |
string |
Variant SKU |
size |
string |
Size value |
color |
string |
Color value |
pattern |
string |
Pattern type |
material |
string |
Material composition |
offers |
ProductOffer |
Variant-specific pricing |
url |
string |
For referencing variants on other pages |
Variant Reference Properties
For multi-page implementations, use these on individual product pages:
| Property | Type | Description |
|---|---|---|
isVariantOf |
{@id: string} \| ProductGroup |
Reference to parent ProductGroup |
inProductGroupWithID |
string |
Parent product group ID |
VariesBy Values
Supported values for the variesBy property:
"size"or"https://schema.org/size""color"or"https://schema.org/color""material"or"https://schema.org/material""pattern"or"https://schema.org/pattern""suggestedAge"or"https://schema.org/suggestedAge""suggestedGender"or"https://schema.org/suggestedGender"
Best Practices for Product Variants
- Use ProductGroup when you have multiple variants of the same product
- Single-page approach: Best when variants are selectable via dropdowns/buttons on one page
- Multi-page approach: Best when each variant needs its own SEO-optimized page
- Always include productGroupID: This links all variants together
- Specify variesBy: Clearly indicate which properties differentiate variants
- Complete variant data: Include as much variant-specific data as possible
- URL references: Use
{ url: "..." }for variants on separate pages - Common properties: Place shared properties (brand, material) at ProductGroup level
- Unique identifiers: Each variant should have unique SKU/GTIN
- Consistent naming: Use clear naming patterns for variants (e.g., "Product - Size Color")
ReviewJsonLd
The ReviewJsonLd component helps you add structured data for reviews to improve their appearance in search results. Reviews can appear as rich snippets with star ratings and review excerpts.
Basic Usage
import { ReviewJsonLd } from "next-seo";
;
Full Review Example
Props
| Property | Type | Description |
|---|---|---|
author |
string \| Person \| Organization |
Required. The author of the review |
reviewRating |
Rating |
Required. The rating given in the review |
itemReviewed |
string \| ItemReviewed |
Required. The item being reviewed |
datePublished |
string |
The date the review was published (ISO 8601) |
reviewBody |
string |
The text of the review |
publisher |
string \| Person \| Organization |
The publisher of the review |
url |
string |
URL of the review |
mainEntityOfPage |
string \| WebPage |
Main entity of the page |
Supported Item Types
Reviews can be written about various types of items:
BookCourseCreativeWorkSeasonCreativeWorkSeriesEpisodeEventGameHowToLocalBusiness(including restaurants)MediaObjectMovieMusicPlaylistMusicRecordingOrganizationProductRecipeSoftwareApplication
Best Practices
- Always include reviewBody: Provides context for the rating
- Use specific item types: Specify
@typeforitemReviewedwhen possible - Include datePublished: Helps establish review freshness
- Author information: Provide as much author detail as possible
- Avoid self-serving reviews: Don't mark up reviews on your own site about your organization
AggregateRatingJsonLd
The AggregateRatingJsonLd component helps you add structured data for aggregate ratings, showing the average rating from multiple reviews.
Basic Usage
import { AggregateRatingJsonLd } from "next-seo";
;
Full Example
With Review Count
Props
| Property | Type | Description |
|---|---|---|
itemReviewed |
string \| ItemReviewed |
Required. The item being rated |
ratingValue |
number \| string |
Required. The average rating value |
ratingCount |
number |
The total number of ratings |
reviewCount |
number |
The number of reviews (at least one of ratingCount or reviewCount is required) |
bestRating |
number |
The highest value in the rating system (default: 5) |
worstRating |
number |
The lowest value in the rating system (default: 1) |
Rating Scale
- Default scale: 1 to 5 stars
- Custom scale: Use
bestRatingandworstRatingto define custom scales - Percentages: Use values like 88 with
bestRating: 100for percentage-based ratings - Fractions: Supports decimal values like 4.4
Best Practices
- Choose the right count: Use
ratingCountfor star ratings,reviewCountfor written reviews - Specify scale for non-standard ratings: Always include
bestRatingandworstRatingfor non-5-star scales - Combine with Product/Organization data: Nest within or alongside main entity structured data
- Minimum threshold: Only use when you have multiple genuine ratings
- Keep it updated: Regularly update aggregate ratings as new reviews come in
Creating Custom Components
Next SEO now supports creating your own custom JSON-LD components using the same utilities and patterns as the built-in components. This allows you to implement any Schema.org type while maintaining the excellent developer experience of next-seo.
Quick Example
import { JsonLdScript, processors } from "next-seo";
export function PodcastEpisodeJsonLd({ name, author, duration, url }) {
const data = {
"@context": "https://schema.org",
"@type": "PodcastEpisode",
name,
...(url && { url }),
...(duration && { duration }),
...(author && { author: processors.processAuthor(author) }),
};
return ;
}
// Usage - no @type needed for author!
;
Key Features
- JsonLdScript Component: Core component for rendering structured data
- 60+ Processors: Transform flexible inputs into Schema.org compliant objects
- @type Optional Pattern: Users never need to specify
@typemanually - TypeScript Support: Full type safety with exported types
Available Utilities
See the processors export file for the complete list of available processors organized by category (People & Organizations, Media & Content, Locations & Places, Commerce & Offers, etc.).
Learn More
For comprehensive documentation on creating custom components, including:
- Using built-in processors
- Creating custom processors
- Advanced patterns and best practices
- Real-world examples
See the Custom Components Guide
Contributors
A massive thank you to everyone who contributes to this project 👏