Next.js Metadata API for SEO, OpenGraph tags, structured data, and social sharing. Use when implementing metadata, SEO, or social media previews.
Provides Next.js metadata guidance for SEO, OpenGraph tags, and structured data. Use when implementing page titles, social sharing previews, or rich search results.
/plugin marketplace add jovermier/cc-stack-marketplace/plugin install cc-nextjs@cc-stack-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Expert guidance for implementing effective metadata in Next.js.
| Concern | Solution | Example |
|---|---|---|
| Page title | metadata object | export const metadata = { title: '...' } |
| Dynamic metadata | generateMetadata function | export async function generateMetadata({ params }) |
| OpenGraph images | metadata.images | openGraph: { images: ['/og.jpg'] } |
| Structured data | Script component | <Script type="application/ld+json"> |
| Canonical URLs | metadata.alternates | canonical: 'https://...' |
| Twitter cards | metadata.twitter | twitter: { card: 'summary_large_image' } |
Specify a number or describe your metadata scenario.
| Response | Reference to Read |
|---|---|
| 1, "static", "metadata", "object" | static-metadata.md |
| 2, "dynamic", "generatemetadata", "params" | dynamic-metadata.md |
| 3, "opengraph", "social", "sharing" | opengraph.md |
| 4, "structured", "json-ld", "schema" | structured-data.md |
| 5, "canonical", "seo", "duplicate" | seo.md |
Every page needs metadata: Title, description, OpenGraph image minimum.
Static for static pages: Use metadata object when values don't change.
Dynamic for dynamic routes: Use generateMetadata when data comes from params or fetch.
OpenGraph for sharing: Ensure pages look good when shared on social media.
Structured data for rich results: Use JSON-LD for articles, products, organizations.
// app/page.tsx
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'My App',
description: 'Description for search engines',
openGraph: {
title: 'My App',
description: 'Description for social sharing',
images: ['/og-image.jpg'],
},
}
export default function Page() {
return <div>...</div>
}
// app/blog/[slug]/page.tsx
import { Metadata } from 'next'
export async function generateMetadata(
{ params }: { params: { slug: string } }
): Promise<Metadata> {
const post = await fetchPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
images: [post.ogImage],
},
}
}
export default function BlogPost({ params }: { params: { slug: string } }) {
// ...
}
import Script from 'next/script'
export default function ArticlePage({ post }: { post: Post }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
datePublished: post.publishedAt,
author: { '@type': 'Person', name: post.author.name },
}
return (
<>
<Script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
<article>{post.content}</article>
</>
)
}
| Element | Required | Format |
|---|---|---|
| title | Yes | string or Metadata.title |
| description | Yes | string (~160 chars) |
| openGraph:title | Yes | string |
| openGraph:description | Yes | string |
| openGraph:image | Yes | string or array (1200x630px min) |
| twitter:card | Recommended | 'summary_large_image' |
| canonical | Recommended | string |
| alternates:languages | Optional | Record<locale, string> |
| Issue | Severity | Fix |
|---|---|---|
| Missing page title | High | Add metadata.title |
| No OpenGraph image | Medium | Add openGraph.images |
| No description | Medium | Add metadata.description |
| Dynamic not using generateMetadata | High | Change to async function |
| Duplicate content (no canonical) | Medium | Add metadata.canonical |
| Small OG image (< 1200x630) | Low | Use larger image |
| File | Topics |
|---|---|
| static-metadata.md | metadata object, all options |
| dynamic-metadata.md | generateMetadata, params, fetch |
| opengraph.md | OG tags, Twitter cards, images |
| structured-data.md | JSON-LD, Script component, schemas |
| seo.md | Canonical, hreflang, robots, sitemap |
Metadata is complete when:
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.