ワンクリックで
nextjs-seo-optimization
SEO optimization for Next.js with metadata and Open Graph. Use for search ranking and social sharing.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
SEO optimization for Next.js with metadata and Open Graph. Use for search ranking and social sharing.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | nextjs-seo-optimization |
| description | SEO optimization for Next.js with metadata and Open Graph. Use for search ranking and social sharing. |
| context | fork |
| globs | ["**/next.config*","**/layout.*","**/metadata.*"] |
| alwaysApply | false |
Use this skill when:
// app/layout.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'MyShop - Best Deals and Coupons',
description: 'Find the best deals from top marketplaces. Exclusive coupons, free shipping and cashback.',
keywords: 'deals, coupons, cashback, free shipping',
metadataBase: new URL('https://myshop.com'),
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://myshop.com',
siteName: 'MyShop',
images: [
{
url: '/og-image.png',
width: 1200,
height: 630,
alt: 'MyShop - Best deals online'
}
]
},
twitter: {
card: 'summary_large_image',
title: 'MyShop',
description: 'Best coupons and deals from top marketplaces',
images: ['/og-image.png']
},
robots: {
index: true,
follow: true,
'max-image-preview': 'large',
'max-snippet': -1,
'max-video-preview': -1,
}
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
{/* Additional meta tags */}
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#FF6B35" />
{/* Preconnect to external domains */}
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
</head>
<body>{children}</body>
</html>
)
}
// app/products/[slug]/page.tsx
import type { Metadata } from 'next'
import { getProduct } from '@/lib/api'
interface Props {
params: { slug: string }
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const product = await getProduct(params.slug)
if (!product) {
return {
title: 'Product not found',
description: 'The requested product does not exist'
}
}
// Dynamic metadata based on product data
return {
title: `${product.title} | MyShop`,
description: product.description.substring(0, 160),
keywords: `${product.title}, coupon, deal, ${product.category}`,
openGraph: {
type: 'product',
url: `https://myshop.com/products/${product.slug}`,
title: product.title,
description: product.description,
images: [
{
url: product.imageUrl,
width: 1200,
height: 630,
alt: product.title
}
]
},
twitter: {
card: 'summary_large_image',
title: product.title,
description: product.description,
images: [product.imageUrl]
}
}
}
export async function generateStaticParams() {
// Generate static pages for most popular products
const products = await getProduct('popular', { limit: 100 })
return products.map((product) => ({
slug: product.slug
}))
}
export default async function ProductPage({ params }: Props) {
const product = await getProduct(params.slug)
if (!product) {
return <div>Product not found</div>
}
return (
<article>
<h1>{product.title}</h1>
<img src={product.imageUrl} alt={product.title} />
<p>{product.description}</p>
</article>
)
}
// app/products/[slug]/page.tsx
import type { Product as SchemaProduct } from 'schema-dts'
import { JsonLd } from 'react-schemaorg'
export default function ProductPage({ product }) {
const schemaData: SchemaProduct = {
'@type': 'Product',
'@context': 'https://schema.org/',
name: product.title,
description: product.description,
image: product.imageUrl,
url: `https://myshop.com/products/${product.slug}`,
sku: product.sku,
brand: {
'@type': 'Brand',
name: product.brand
},
offers: {
'@type': 'Offer',
url: `https://myshop.com/products/${product.slug}`,
priceCurrency: 'USD',
price: product.price.toString(),
priceValidUntil: product.expiresAt,
availability: product.inStock ? 'InStock' : 'OutOfStock',
seller: {
'@type': 'Organization',
name: 'MyShop'
}
},
aggregateRating: product.rating ? {
'@type': 'AggregateRating',
ratingValue: product.rating.score,
ratingCount: product.rating.count
} : undefined
}
return (
<>
<JsonLd<SchemaProduct> item={schemaData} />
<article>
<h1>{product.title}</h1>
{/* Product content */}
</article>
</>
)
}
// app/sitemap.ts
import { MetadataRoute } from 'next'
import { getAllProducts } from '@/lib/api'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://myshop.com'
// Static routes
const staticRoutes: MetadataRoute.Sitemap = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1
},
{
url: `${baseUrl}/products`,
lastModified: new Date(),
changeFrequency: 'hourly',
priority: 0.9
},
{
url: `${baseUrl}/categories`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8
},
{
url: `${baseUrl}/about`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.5
}
]
// Dynamic routes (products)
const products = await getAllProducts()
const productRoutes: MetadataRoute.Sitemap = products.map((product) => ({
url: `${baseUrl}/products/${product.slug}`,
lastModified: new Date(product.updatedAt),
changeFrequency: 'weekly' as const,
priority: 0.7
}))
return [...staticRoutes, ...productRoutes]
}
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/admin', '/api', '/*.json$'],
},
{
userAgent: 'GPTBot',
disallow: '/',
},
],
sitemap: 'https://myshop.com/sitemap.xml',
}
}
// components/CanonicalURL.tsx
interface CanonicalURLProps {
path: string
baseUrl?: string
}
export function CanonicalURL({ path, baseUrl = 'https://myshop.com' }: CanonicalURLProps) {
return (
<link
rel="canonical"
href={`${baseUrl}${path}`}
key="canonical"
/>
)
}
// Usage in page.tsx
export const metadata: Metadata = {
// ... other metadata
other: {
canonical: 'https://myshop.com/products/smartphone-xyz'
}
}
// components/OptimizedImage.tsx
import Image from 'next/image'
interface OptimizedImageProps {
src: string
alt: string
title?: string
width?: number
height?: number
}
export function OptimizedImage({
src,
alt,
title,
width = 800,
height = 600
}: OptimizedImageProps) {
return (
<Image
src={src}
alt={alt}
title={title || alt}
width={width}
height={height}
quality={85}
priority={false}
placeholder="blur"
blurDataURL="data:image/webp;base64,..." // Placeholder
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
)
}
// app/products/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og'
import { getProduct } from '@/lib/api'
export const runtime = 'nodejs'
export const alt = 'Product preview'
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
interface Props {
params: { slug: string }
}
export default async function Image({ params }: Props) {
const product = await getProduct(params.slug)
return new ImageResponse(
(
<div
style={{
fontSize: 48,
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
padding: '40px',
}}
>
<div>
<h1>{product.title}</h1>
<p>💰 ${product.price}</p>
<p>⭐ {product.rating}/5</p>
</div>
</div>
),
{
...size,
},
)
}
// hooks/useSEOChecklist.ts
export function useSEOChecklist(page: string) {
const checks = {
homepage: [
'✅ Title tag (50-60 chars)',
'✅ Meta description (150-160 chars)',
'✅ H1 tag (only one)',
'✅ Open Graph image (1200x630)',
'✅ Mobile responsive',
'✅ Core Web Vitals score',
'✅ Schema markup (Organization)',
'✅ robots.txt configured',
'✅ sitemap.xml present',
'✅ Canonical URL set'
],
productPage: [
'✅ Product title in H1',
'✅ Product image optimized',
'✅ Price structured data',
'✅ Rating schema markup',
'✅ Dynamic meta description',
'✅ Open Graph tags dynamic',
'✅ Canonical URL set',
'✅ Related products linked',
'✅ Breadcrumb schema',
'✅ No duplicate content'
]
}
return checks[page] || []
}
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'cdn.example.com',
},
{
protocol: 'https',
hostname: 'aliexpress.com',
},
],
minimumCacheSize: 50,
formats: ['image/webp', 'image/avif'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
// ISR configuration
onDemandEntries: {
maxInactiveAge: 60 * 10 * 1000, // 10 min
pagesBufferLength: 5,
},
// Headers for SEO
headers: async () => [
{
source: '/:path*',
headers: [
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN'
},
{
key: 'X-XSS-Protection',
value: '1; mode=block'
}
]
}
]
}
module.exports = nextConfig
✅ Title: 50-60 characters, keyword at start
✅ Description: 150-160 characters, compelling CTA
✅ H1: One per page, keyword relevant
✅ Images: Optimized, descriptive alt text
✅ Links: Internal linking strategy, no orphaned pages
✅ Mobile: Fully responsive, Core Web Vitals ≥ 75
✅ Speed: Images optimized, code splitting
✅ Schema: Product, Organization, BreadcrumbList
✅ Canonicals: Set for paginated/filtered content
✅ Structured Data: Tested with Google Schema Validator
Tool-agnostic search — query construction, tool selection, source trust hierarchy.
Auto-continue through todos with idle detection and safety gates. Use for multi-step orchestration.
Level 2 — Pantheon-native context compression with priority scoring, semantic summarization, downstream-aware compression, budget allocation, and cross-references
Automated visual review pipeline — Playwright screenshots, self-analysis, fix loop, escalation. Used by Aphrodite for UI verification.
Multi-agent orchestration with model routing, category delegation, and sprint management. Use for coordinating Pantheon agents.
MCP security hardening — credential leakage prevention, input sanitization, and tool access control. Use for reviewing agent MCP configurations.