generating-seo-metadata

SEO Metadata Generator

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "generating-seo-metadata" with this command: npx skills add wesleysmits/agent-skills/wesleysmits-agent-skills-generating-seo-metadata

SEO Metadata Generator

When to use this skill

  • User asks to add meta tags to a page

  • User mentions Open Graph or social sharing

  • User wants JSON-LD or structured data

  • User asks about hreflang or internationalization

  • User wants to improve SEO or search visibility

Workflow

  • Identify page type and intent

  • Generate base meta tags

  • Create Open Graph tags

  • Add Twitter Card meta

  • Generate JSON-LD structured data

  • Add hreflang if multilingual

  • Validate output

Instructions

Step 1: Identify Page Type

Determine content type to select appropriate schema:

Page Type JSON-LD Schema Priority Meta

Homepage Organization, WebSite Brand, description

Article/Blog Article, BlogPosting Author, date, image

Product Product, Offer Price, availability

Service Service, LocalBusiness Provider, area

FAQ FAQPage Questions

Event Event Date, location, price

Person/About Person, ProfilePage Name, role

Contact ContactPage, LocalBusiness Address, phone

Step 2: Generate Base Meta Tags

Essential meta tags:

<head> <!-- Primary Meta --> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{Page Title} | {Site Name}</title> <meta name="description" content="{150-160 char description}" />

<!-- Indexing Control --> <meta name="robots" content="index, follow" /> <link rel="canonical" href="https://example.com/page-url" />

<!-- Optional --> <meta name="author" content="{Author Name}" /> <meta name="keywords" content="{keyword1, keyword2, keyword3}" /> </head>

Title guidelines:

  • 50-60 characters max

  • Primary keyword near the start

  • Include brand name with separator

  • Unique per page

Description guidelines:

  • 150-160 characters

  • Include primary keyword naturally

  • Call to action when appropriate

  • Unique per page

Step 3: Open Graph Tags

Core Open Graph:

<!-- Open Graph --> <meta property="og:type" content="website" /> <meta property="og:url" content="https://example.com/page" /> <meta property="og:title" content="{Title for social sharing}" /> <meta property="og:description" content="{Description for social sharing}" /> <meta property="og:image" content="https://example.com/og-image.jpg" /> <meta property="og:image:width" content="1200" /> <meta property="og:image:height" content="630" /> <meta property="og:image:alt" content="{Image description}" /> <meta property="og:site_name" content="{Site Name}" /> <meta property="og:locale" content="en_US" />

Article-specific:

<meta property="og:type" content="article" /> <meta property="article:published_time" content="2026-01-18T10:00:00Z" /> <meta property="article:modified_time" content="2026-01-18T12:00:00Z" /> <meta property="article:author" content="https://example.com/author" /> <meta property="article:section" content="Technology" /> <meta property="article:tag" content="JavaScript" />

Product-specific:

<meta property="og:type" content="product" /> <meta property="product:price:amount" content="29.99" /> <meta property="product:price:currency" content="USD" /> <meta property="product:availability" content="in stock" />

Step 4: Twitter Card Meta

<!-- Twitter Card --> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:site" content="@sitehandle" /> <meta name="twitter:creator" content="@authorhandle" /> <meta name="twitter:title" content="{Title}" /> <meta name="twitter:description" content="{Description}" /> <meta name="twitter:image" content="https://example.com/twitter-image.jpg" /> <meta name="twitter:image:alt" content="{Image description}" />

Card types:

  • summary : Small square image

  • summary_large_image : Large rectangular image

  • player : Video/audio embed

  • app : App install card

Step 5: JSON-LD Structured Data

Article schema:

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "headline": "Article Title Here", "description": "Article description", "image": "https://example.com/image.jpg", "author": { "@type": "Person", "name": "Author Name", "url": "https://example.com/author" }, "publisher": { "@type": "Organization", "name": "Site Name", "logo": { "@type": "ImageObject", "url": "https://example.com/logo.png" } }, "datePublished": "2026-01-18", "dateModified": "2026-01-18" } </script>

Product schema:

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Product", "name": "Product Name", "description": "Product description", "image": "https://example.com/product.jpg", "brand": { "@type": "Brand", "name": "Brand Name" }, "offers": { "@type": "Offer", "url": "https://example.com/product", "priceCurrency": "USD", "price": "29.99", "availability": "https://schema.org/InStock", "seller": { "@type": "Organization", "name": "Store Name" } }, "aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.5", "reviewCount": "42" } } </script>

FAQ schema:

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [ { "@type": "Question", "name": "What is the question?", "acceptedAnswer": { "@type": "Answer", "text": "This is the answer." } } ] } </script>

LocalBusiness schema:

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "LocalBusiness", "name": "Business Name", "image": "https://example.com/photo.jpg", "address": { "@type": "PostalAddress", "streetAddress": "123 Main St", "addressLocality": "City", "addressRegion": "State", "postalCode": "12345", "addressCountry": "US" }, "telephone": "+1-555-555-5555", "openingHoursSpecification": { "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], "opens": "09:00", "closes": "17:00" } } </script>

BreadcrumbList schema:

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com" }, { "@type": "ListItem", "position": 2, "name": "Category", "item": "https://example.com/category" }, { "@type": "ListItem", "position": 3, "name": "Current Page" } ] } </script>

Step 6: Hreflang for Multilingual Sites

<!-- Language alternates --> <link rel="alternate" hreflang="en" href="https://example.com/page" /> <link rel="alternate" hreflang="nl" href="https://example.nl/pagina" /> <link rel="alternate" hreflang="de" href="https://example.de/seite" /> <link rel="alternate" hreflang="x-default" href="https://example.com/page" />

Common hreflang codes:

Language Code With Region

English en

en-US , en-GB

Dutch nl

nl-NL , nl-BE

German de

de-DE , de-AT

French fr

fr-FR , fr-CA

Spanish es

es-ES , es-MX

Framework Integration

Next.js (App Router):

// app/page.tsx import { Metadata } from "next";

export const metadata: Metadata = { title: "Page Title | Site Name", description: "Page description here", openGraph: { title: "OG Title", description: "OG Description", url: "https://example.com/page", siteName: "Site Name", images: [ { url: "https://example.com/og.jpg", width: 1200, height: 630, alt: "Image alt", }, ], locale: "en_US", type: "website", }, twitter: { card: "summary_large_image", title: "Twitter Title", description: "Twitter description", images: ["https://example.com/twitter.jpg"], }, alternates: { canonical: "https://example.com/page", languages: { en: "https://example.com/page", nl: "https://example.nl/pagina", }, }, };

Next.js JSON-LD:

// app/page.tsx export default function Page() { const jsonLd = { "@context": "https://schema.org", "@type": "Article", headline: "Article Title", // ... rest of schema };

return ( <> <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} /> {/* Page content */} </> ); }

Nuxt 3:

<script setup lang="ts"> useSeoMeta({ title: "Page Title", description: "Page description", ogTitle: "OG Title", ogDescription: "OG Description", ogImage: "https://example.com/og.jpg", ogUrl: "https://example.com/page", twitterCard: "summary_large_image", });

useHead({ link: [{ rel: "canonical", href: "https://example.com/page" }], script: [ { type: "application/ld+json", children: JSON.stringify({ "@context": "https://schema.org", "@type": "Article", // ... schema }), }, ], }); </script>

Validation

Before completing:

  • Title under 60 characters

  • Description 150-160 characters

  • Canonical URL set

  • OG image is 1200x630px

  • JSON-LD validates at schema.org validator

  • All URLs are absolute

  • Hreflang includes x-default

Validation tools:

Test JSON-LD locally

curl -s "https://validator.schema.org/" # Use web interface

Check meta tags

curl -s https://example.com | grep -E '<meta|<title|<link rel="canonical"'

Error Handling

  • Missing required fields: JSON-LD requires certain fields per type; validate against schema.org.

  • Image dimensions wrong: OG images must be at least 200x200, recommended 1200x630.

  • Duplicate canonical: Only one canonical URL per page.

  • Hreflang loops: Each language version must link to all others including itself.

  • Invalid dates: Use ISO 8601 format (YYYY-MM-DD or full datetime).

Resources

  • Schema.org Full Hierarchy

  • Google Rich Results Test

  • Open Graph Protocol

  • Twitter Cards Documentation

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

writing-product-descriptions

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

writing-press-releases

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

creating-podcast-show-notes

No summary provided by upstream source.

Repository SourceNeeds Review