@masters-ws/react-seo
v2.0.0
Published
Professional SSR-first SEO toolkit for React/Next.js — Twitter/X Cards, Open Graph, 30+ schemas, rich-result validation, Smart Glide social images, zero-dependency core.
Maintainers
Readme
@masters-ws/react-seo
Professional SEO toolkit for React & Next.js — SSR-first, zero-dependency core, Twitter/X Cards, Open Graph, 30+ schema types, Google rich-result validation, Smart Glide social images, and a built-in development auditor.
✨ What's New in v2.0
| Area | Upgrade |
|---|---|
| Twitter / X Cards | Separate site vs creator, image dimensions, player + app card fields |
| Social images | buildSocialImageUrl / resolveOgImage / resolveTwitterImage (Smart Glide compatible) |
| One-call helpers | generateFAQMetadata, generateLocalBusinessMetadata, generateAuthorMetadata, generateTagMetadata |
| Rich Results | validateRichResults() for Product, Article, FAQ, LocalBusiness, Person |
| Types | Strict NextCompatibleMetadata (zero next dependency on core) |
| hreflang | buildHreflangAlternates() with x-default |
| Tests | Vitest suite for metadata, Twitter, social images, validators, helpers |
Why @masters-ws/react-seo?
Most SEO packages inject metadata client-side — after JavaScript loads. Google crawls your page before that. This package fixes that.
| Feature | @masters-ws/react-seo | next-seo | react-helmet |
|---|---|---|---|
| Zero-dependency core | ✅ | ❌ | ❌ |
| SSR-first (App Router) | ✅ | ✅ | ❌ |
| @graph JSON-LD | ✅ | ❌ | ❌ |
| One-call page setup | ✅ | ❌ | ❌ |
| Twitter/X Cards (full) | ✅ | partial | ❌ |
| Smart Glide social images | ✅ | ❌ | ❌ |
| Rich-result validation | ✅ | ❌ | ❌ |
| Integrated SEO Auditor | ✅ | ❌ | ❌ |
| Built-in pagination SEO | ✅ | partial | ❌ |
Installation
# Next.js App Router (zero dependencies)
npm install @masters-ws/react-seo
# React / Next.js Pages Router
npm install @masters-ws/react-seo react-helmet-async🔍 SEO Auditor (Development Only)
This library includes a built-in SEO Auditor component designed to speed up your development workflow by providing a real-time analysis of your page's SEO status directly in your browser.
- Real-Time Analysis: Scans for title/description lengths, H1 counts, missing alt tags, and more.
- Visual Previews: Live mockups for Google Search results and Social Media cards.
- Production Safe: Only renders when
process.env.NODE_ENV === 'development'.
Usage:
// app/layout.tsx (Next.js App Router)
import { SEOAuditor } from '@masters-ws/react-seo';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<SEOAuditor />
</body>
</html>
);
}🚀 Quick Start: Next.js App Router (Recommended)
Product Page — One-Call Setup
// app/products/[slug]/page.tsx
import { generateProductMetadata, JsonLd } from '@masters-ws/react-seo/core';
const siteConfig = {
name: "My Store",
url: "https://store.com",
logo: "https://store.com/logo.png",
description: "Best online store",
language: "en_US",
};
export async function generateMetadata({ params }) {
const product = await fetchProduct(params.slug);
const { metadata } = generateProductMetadata({
name: product.name,
description: product.short_description,
image: [product.main_image, ...product.gallery],
price: product.price,
currency: "USD",
sku: product.sku,
brand: product.brand?.name,
availability: product.in_stock
? "https://schema.org/InStock"
: "https://schema.org/OutOfStock",
url: `https://store.com/products/${params.slug}`,
breadcrumbs: [
{ name: "Home", item: "https://store.com" },
{ name: product.category?.name, item: `https://store.com/categories/${product.category?.slug}` },
{ name: product.name, item: `https://store.com/products/${params.slug}` },
],
}, siteConfig);
return metadata;
}
export default async function ProductPage({ params }) {
const product = await fetchProduct(params.slug);
const { schemas } = generateProductMetadata({ /* same options */ }, siteConfig);
return (
<>
<JsonLd schema={schemas} graph />
<ProductDetailClient product={product} />
</>
);
}What Google sees in the HTML source:
<title>Product Name | My Store</title>
<meta name="description" content="..." />
<meta property="og:title" content="Product Name" />
<meta property="og:image" content="https://store.com/product.jpg" />
<link rel="canonical" href="https://store.com/products/my-product" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{ "@type": "Product", "name": "...", "offers": {...} },
{ "@type": "BreadcrumbList", "itemListElement": [...] },
{ "@type": "Organization", "name": "..." },
{ "@type": "WebSite", "potentialAction": {...} }
]
}
</script>Core Functions
One-Call Helpers (Recommended)
| Function | Generates |
|---|---|
| generateProductMetadata(product, config) | Metadata + Product, Breadcrumb, Organization, WebSite schemas |
| generateArticleMetadata(article, config) | Metadata + NewsArticle, Breadcrumb, Organization, WebSite schemas |
| generateCategoryMetadata(category, config) | Metadata + CollectionPage, Breadcrumb, ItemList schemas |
| generateHomepageMetadata(input, config) | Metadata + WebPage, Organization, WebSite, optional LocalBusiness |
| generateFAQMetadata(input, config) | Metadata + FAQPage (+ breadcrumbs / WebPage) |
| generateLocalBusinessMetadata(input, config) | Metadata + LocalBusiness page bundle |
| generateAuthorMetadata(input, config) | Metadata + Person schema (author pages) |
| generateTagMetadata(input, config) | Metadata + tag/topic archive bundle |
Twitter / X Cards
Fully supported in both toNextMetadata (App Router) and <SEO /> (Helmet).
const siteConfig = {
name: 'Demo',
url: 'https://demo.com',
description: '…',
twitterHandle: '@demostore', // twitter:site
};
toNextMetadata({
title: 'Summer Launch',
description: 'Our biggest drop yet',
image: 'covers/summer.jpg',
twitterCard: 'summary_large_image',
twitterCreator: '@editor', // overrides site handle for creator
twitterImageWidth: 1200,
twitterImageHeight: 628,
author: { name: 'Sara', twitterHandle: 'sara' }, // also sets creator
}, siteConfig);| Card | Support |
|---|---|
| summary | ✅ |
| summary_large_image | ✅ (default) |
| player | ✅ via twitterPlayer (player, width/height, stream) |
| app | ✅ via twitterApp (iPhone / iPad / Google Play ids) |
Smart Glide social images
Optimize OG / Twitter images through your Smart Glide delivery endpoint — optional, zero hard dependency.
const siteConfig = {
name: 'Demo',
url: 'https://demo.com',
description: '…',
imageDelivery: {
baseUrl: 'https://demo.com',
deliveryPath: '/api/img', // Smart Glide handler
defaultQuality: 82,
},
};
// Relative paths become:
// https://demo.com/api/img/products/phone.jpg?w=1200&h=630&q=82&fm=webp&fit=cover
const { metadata } = generateProductMetadata({
name: 'Phone',
description: '…',
url: 'https://demo.com/p/1',
image: 'products/phone.jpg',
}, siteConfig);Helpers: buildSocialImageUrl, resolveOgImage, resolveTwitterImage.
Rich-result validation
import { validateRichResults, generateProductSchema } from '@masters-ws/react-seo/core';
const schema = generateProductSchema({ name: 'X', /* … */ });
const report = validateRichResults('Product', schema);
if (!report.ok) {
console.error(report.errors);
}Supported rule sets: Product, Article / NewsArticle, FAQPage, LocalBusiness, Person, BreadcrumbList.
Multilingual (hreflang)
import { buildHreflangAlternates, toNextMetadata } from '@masters-ws/react-seo/core';
const { list, languages } = buildHreflangAlternates(
[
{ locale: 'en', href: 'https://demo.com/en/page' },
{ locale: 'ar', href: 'https://demo.com/ar/page' },
],
'https://demo.com/page' // x-default
);
return toNextMetadata({
title: 'Page',
alternates: list,
canonical: 'https://demo.com/en/page',
}, siteConfig);Schema Generators
| Function | Schema Type |
|---|---|
| generateProductSchema(data) | Product — multi-image, reviews, return policy, shipping, variants |
| generateArticleSchema(data, config) | NewsArticle |
| generateFAQSchema(questions) | FAQPage |
| generateBreadcrumbSchema(items) | BreadcrumbList |
| generateLocalBusinessSchema(data) | LocalBusiness |
| generateOrganizationSchema(config) | Organization |
| generateWebSiteSchema(config) | WebSite with SearchAction |
| generateWebPageSchema(data, config) | WebPage |
| generateHowToSchema(data) | HowTo |
| generateRecipeSchema(data) | Recipe |
| generateJobPostingSchema(data) | JobPosting |
| generateEventSchema(data) | Event |
| generateVideoSchema(data) | VideoObject |
Utilities
| Function | Description |
|---|---|
| toNextMetadata(data, config) | Converts SEO data to Next.js Metadata object |
| cleanSchema(obj) | Removes undefined/null from schema objects |
| validateSEO(type, data, fields) | Dev-only warnings for missing required fields |
<JsonLd> Component
// Multiple separate <script> tags
<JsonLd schema={[productSchema, breadcrumbSchema]} />
// Single @graph block (Google recommended)
<JsonLd schema={[productSchema, breadcrumbSchema, orgSchema]} graph />Product Schema — Advanced Features
Reviews + Ratings
generateProductSchema({
name: "T-Shirt",
rating: 4.5,
reviewCount: 128,
reviews: [
{ author: "Alice", ratingValue: 5, reviewBody: "Amazing quality!", datePublished: "2024-01-15" },
{ author: "Bob", ratingValue: 4, reviewBody: "Good value", datePublished: "2024-02-01" },
],
});Return Policy
generateProductSchema({
returnPolicy: {
returnPolicyCategory: "MerchantReturnFiniteReturnWindow",
returnWithin: 30,
returnMethod: "ReturnByMail",
returnFees: "FreeReturn",
},
});Shipping
generateProductSchema({
shipping: {
shippingRate: { value: 5.99, currency: "USD" },
shippingDestination: "US",
deliveryTime: { minDays: 3, maxDays: 7 },
freeShippingThreshold: 50,
},
});Product Variants → AggregateOffer
generateProductSchema({
variants: [
{ name: "Small", sku: "TS-S", price: 19.99 },
{ name: "Medium", sku: "TS-M", price: 22.99 },
{ name: "Large", sku: "TS-L", price: 24.99 },
],
});
// → AggregateOffer { lowPrice: 19.99, highPrice: 24.99, offerCount: 3 }React / Pages Router
// _app.tsx
import { SEOProvider } from '@masters-ws/react-seo';
export default function App({ Component, pageProps }) {
return (
<SEOProvider config={{ name: "My Site", url: "https://mysite.com", description: "..." }}>
<Component {...pageProps} />
</SEOProvider>
);
}
// pages/products/[id].tsx
import { SeoProduct } from '@masters-ws/react-seo';
export default function ProductPage({ product }) {
return (
<>
<SeoProduct item={{
name: product.name,
description: product.description,
image: product.image,
price: product.price,
currency: "USD",
sku: product.sku,
}} />
<main>...</main>
</>
);
}⚠️ SSR vs CSR
// ✅ Correct — Server Component, Google sees everything
import { generateProductMetadata, JsonLd } from '@masters-ws/react-seo/core';
export async function generateMetadata() { /* ... */ }
export default function Page() {
return <JsonLd schema={schemas} graph />;
}
// ❌ Wrong — 'use client' means metadata loads after JS
'use client';
export default function Page() {
return <SEO title="..." />; // Google may miss this
}Generating SEO-Optimized Content
This package handles technical SEO perfectly. For generating the actual content that ranks — blog posts, product descriptions, landing pages — pair it with Outrank, the AI platform built specifically for SEO content at scale.
🚀 Get Started: outrank.so
🎁 Exclusive: Use code SHADI for 10% off your first month.
License
MIT © Shadi Shammaa
