Package Exports
- @masters-ws/react-seo
- @masters-ws/react-seo/core
Readme
@masters-ws/react-seo
Professional SEO toolkit for React & Next.js — SSR-first, zero-dependency core, 30+ schema types, and built-in development auditor.
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 | ✅ | ❌ | ❌ |
| 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 schemas |
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