Claude Code Plugins

Community-maintained marketplace

Feedback

Add SEO meta tags, Open Graph tags, and structured data to routes. Use when optimizing pages for search engines or social sharing.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name add-seo
description Add SEO meta tags, Open Graph tags, and structured data to routes. Use when optimizing pages for search engines or social sharing.

Add SEO

Adds SEO optimization including meta tags, Open Graph, Twitter cards, and structured data using React 19 patterns.

When to Use

  • Adding page titles and descriptions
  • Setting up Open Graph for social sharing
  • Adding Twitter card metadata
  • Implementing structured data (JSON-LD)
  • User asks to "add SEO", "add meta tags", or "optimize for search"

React 19 Meta Pattern

Use native JSX tags, NOT meta() export.

import type { Route } from './+types/product';

export default function ProductPage({ loaderData }: Route.ComponentProps) {
    const { product } = loaderData;

    return (
        <>
            {/* Required */}
            <title>{product.name} | Iridium</title>
            <meta name="description" content={product.description} />

            {/* Open Graph */}
            <meta property="og:title" content={product.name} />
            <meta property="og:description" content={product.description} />
            <meta property="og:image" content={product.imageUrl} />
            <meta property="og:type" content="product" />
            <meta property="og:url" content={`https://example.com/products/${product.id}`} />

            {/* Twitter Card */}
            <meta name="twitter:card" content="summary_large_image" />
            <meta name="twitter:title" content={product.name} />
            <meta name="twitter:description" content={product.description} />
            <meta name="twitter:image" content={product.imageUrl} />

            {/* Page content */}
            <Container>
                <h1>{product.name}</h1>
            </Container>
        </>
    );
}

Basic Page SEO

export default function AboutPage() {
    return (
        <>
            <title>About Us | Iridium</title>
            <meta name="description" content="Learn about our mission, team, and values." />
            <meta name="robots" content="index, follow" />

            <Container>
                {/* Page content */}
            </Container>
        </>
    );
}

Dynamic SEO from Loader Data

import type { Route } from './+types/blog-post';

export async function loader({ params }: Route.LoaderArgs) {
    const post = await getPost(params.slug);
    return { post };
}

export default function BlogPost({ loaderData }: Route.ComponentProps) {
    const { post } = loaderData;
    const canonicalUrl = `https://example.com/blog/${post.slug}`;

    return (
        <>
            <title>{post.title} | Blog | Iridium</title>
            <meta name="description" content={post.excerpt} />
            <link rel="canonical" href={canonicalUrl} />

            {/* Article-specific Open Graph */}
            <meta property="og:type" content="article" />
            <meta property="og:title" content={post.title} />
            <meta property="og:description" content={post.excerpt} />
            <meta property="og:image" content={post.featuredImage} />
            <meta property="og:url" content={canonicalUrl} />
            <meta property="article:published_time" content={post.publishedAt} />
            <meta property="article:author" content={post.author.name} />

            <Container>
                <article>
                    <h1>{post.title}</h1>
                    {/* Post content */}
                </article>
            </Container>
        </>
    );
}

Structured Data (JSON-LD)

import type { Route } from './+types/product';

export default function ProductPage({ loaderData }: Route.ComponentProps) {
    const { product } = loaderData;

    const structuredData = {
        '@context': 'https://schema.org',
        '@type': 'Product',
        name: product.name,
        description: product.description,
        image: product.imageUrl,
        offers: {
            '@type': 'Offer',
            price: product.price,
            priceCurrency: 'USD',
            availability: 'https://schema.org/InStock',
        },
    };

    return (
        <>
            <title>{product.name} | Iridium</title>
            <meta name="description" content={product.description} />

            {/* Structured Data */}
            <script
                type="application/ld+json"
                dangerouslySetInnerHTML={{
                    __html: JSON.stringify(structuredData),
                }}
            />

            <Container>
                {/* Product content */}
            </Container>
        </>
    );
}

Organization Structured Data

const organizationData = {
    '@context': 'https://schema.org',
    '@type': 'Organization',
    name: 'Iridium',
    url: 'https://example.com',
    logo: 'https://example.com/logo.png',
    sameAs: [
        'https://twitter.com/iridium',
        'https://github.com/iridium',
    ],
};

Breadcrumb Structured Data

const breadcrumbData = {
    '@context': 'https://schema.org',
    '@type': 'BreadcrumbList',
    itemListElement: [
        {
            '@type': 'ListItem',
            position: 1,
            name: 'Home',
            item: 'https://example.com',
        },
        {
            '@type': 'ListItem',
            position: 2,
            name: 'Products',
            item: 'https://example.com/products',
        },
        {
            '@type': 'ListItem',
            position: 3,
            name: product.name,
            item: `https://example.com/products/${product.id}`,
        },
    ],
};

No-Index Pages

For pages that shouldn't appear in search:

export default function PrivatePage() {
    return (
        <>
            <title>Private Page | Iridium</title>
            <meta name="robots" content="noindex, nofollow" />
            {/* Content */}
        </>
    );
}

SEO Checklist

  • Unique <title> for each page (50-60 chars)
  • <meta name="description"> (150-160 chars)
  • Open Graph tags for social sharing
  • Twitter Card tags
  • Canonical URL for duplicate content
  • Structured data where appropriate
  • No-index on private pages

Anti-Patterns

  • Using meta() export (old pattern)
  • Duplicate titles across pages
  • Missing descriptions
  • Descriptions over 160 characters
  • Missing Open Graph image
  • Using same meta on all pages

Full Reference

See .github/instructions/seo.instructions.md for comprehensive documentation.