pseo-metadata
Skill54 starsChanged 15 days agoMITView on GitHub
Implement fully dynamic SEO metadata including title tags, meta descriptions, canonical URLs, Open Graph tags, and Twitter cards for programmatic SEO pages. Use when setting up or fixing metadata, adding OG/Twitter tags, implementing canonical URLs, or when metadata is static, duplicated, or missing across pSEO pages.
- Reads credentials
1 other project uses a version of this, 1 of them edited.
Adopted by
Most recently taken up by
- karrolcia/hippocampusedited, first seen Mar 2, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 1
- karrolcia/hippocampus★ 1371% same
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository17 other files it gives its agents.
- gscSkill
- pseo-auditSkill
- pseo-dataSkill
- pseo-discoverySkill
- pseo-linkingSkill
- pseo-llm-visibilitySkill
- pseo-orchestrateSkill
- pseo-performanceSkill
- pseo-quality-guardSkill
- pseo-scaleSkill
- pseo-schemaSkill
- pseo-templatesSkill
- seo-content-refreshSkill
- seo-i18nSkill
- seo-log-analysisSkill
- seo-migrationSkill
- seo-regression-guardSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
19 rules. About 0 are common, 15 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈15
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Every page gets unique metadata: No two pages share the same title or description
- Very specific: line 16
Canonical by default: Every page declares its canonical URL, in the <head> of the initial HTML
- Distinctive: line 18
Framework-native: Use the framework's built-in metadata API
- Distinctive: line 69
Multi-dimensional: Use 2+ data fields to construct, not just one variable
- Very specific: line 91
Every page must set a self-referencing canonical URL in the <head> (Google's canonical docs specify the head section)
- Distinctive: line 92
If JavaScript sets or changes the canonical, it must equal the canonical in the original HTML, or leave it out of the original HTML …
- Distinctive: line 93
Use absolute URLs (include protocol and domain)
- Distinctive: line 96
If a page has query parameters, the canonical should point to the clean URL
- Very specific: line 129
Do not use noindex to save crawl budget.
- Distinctive: line 153
Keep head tags first and the HTML small.
- Very specific: line 193
Verify with curl -s URL | grep -i canonical and check the tag appears inside <head>.
- Distinctive: line 201
Run these checks (or integrate with pseo-quality-guard):
- Distinctive: line 202
No two pages produce the same title
- Distinctive: line 203
No two pages produce the same description
- Distinctive: line 204
All titles are between 30-70 characters
- Distinctive: line 205
All descriptions are between 100-170 characters
- Distinctive: line 206
All canonical URLs resolve to 200 status
- Distinctive: line 209
All OG tags are present on every page
- Distinctive: line 210
No page is missing metadata entirely
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
pSEO Dynamic Metadata
Implement a metadata system that generates unique, accurate SEO tags for every programmatic page.
Core Principles
- Every page gets unique metadata: No two pages share the same title or description
- Data-driven generation: Metadata is constructed from structured content fields, not hardcoded
- Canonical by default: Every page declares its canonical URL, in the
<head>of the initial HTML - Social-ready: Open Graph and Twitter cards are complete on every page, with a page-specific or per-category image (never one site-wide placeholder)
- Framework-native: Use the framework's built-in metadata API
Scope parameter
all (default) = everything. titles = section 2, descriptions = section 3, canonical = section 4 (and 8a), opengraph = section 5, twitter = section 6, robots = sections 7, 7a, 7b, export = sections 8 and 8a, i18n = section 9.
Implementation Steps
1. Create the Metadata Generator
Build a centralized function that constructs metadata from page data:
Next.js App Router pattern:
// lib/metadata.ts
import type { Metadata } from "next";
export function generatePageMetadata(data: PageData, baseUrl: string): Metadata {
const title = buildTitle(data);
const description = buildDescription(data);
const canonicalUrl = `${baseUrl}${data.canonicalPath}`;
return {
title,
description,
alternates: { canonical: canonicalUrl },
openGraph: {
title,
description,
url: canonicalUrl,
type: "article",
siteName: "Site Name",
// images: [{ url, width, height, alt }],
},
twitter: {
card: "summary_large_image",
title,
description,
// images: [url],
},
};
}2. Build Title Construction Logic
Titles must be:
- Unique across all pages (validate with pseo-quality-guard)
- 50-60 characters target length (hard cap at 70)
- Front-loaded with the primary keyword
- Accurate to the page: Google may rewrite titles that are stuffed, boilerplate or do not describe the page. Do not fight rewrites with more keywords; make the title and H1 agree and describe the content.
- Multi-dimensional: Use 2+ data fields to construct, not just one variable
function buildTitle(data: PageData): string {
// Combine multiple data dimensions
// e.g., "{primary keyword} - {differentiator} | {brand}"
// NOT just "{keyword} | Brand" for every page
}3. Build Description Construction Logic
Descriptions must be:
- Unique across all pages
- 150-160 characters target length
- Action-oriented: Include a value proposition or call to action
- Keyword-inclusive: Naturally incorporate the page's target keyword
- Google often shows its own snippet instead of the meta description. Write it for users, not as a ranking lever.
- Review generated titles and descriptions by hand. Google says to fact-check all AI-generated titles and meta descriptions.
4. Implement Canonical URLs
- Every page must set a self-referencing canonical URL in the
<head>(Google's canonical docs specify the head section) - If JavaScript sets or changes the canonical, it must equal the canonical in the original HTML, or leave it out of the original HTML (Google, 2025-12-17)
- Use absolute URLs (include protocol and domain)
- Canonicals must match the actual URL path exactly (no trailing slash mismatches)
- For paginated content, each page gets its own canonical
- If a page has query parameters, the canonical should point to the clean URL
- For paginated content, never point every page at page 1
- Near-duplicate template pages split into separate canonicals faster when the difference is clear and significant. After fixing duplicates, Google may hold a cluster for up to two weeks.
5. Configure Open Graph Tags
Required OG tags for every pSEO page:
og:title- Can differ from the HTML title (no brand suffix needed)og:description- Can differ from meta descriptionog:url- Must match canonicalog:type- Usually "article" for content pages, "website" for hubsog:site_name- Consistent across all pagesog:image- Page-specific image, else a per-category image generated withopengraph-image.tsx(ImageResponse); never one site-wide placeholder. Always include alt textog:locale- Language/locale setting
Image SEO for these images (details in pseo-templates section 9):
- Descriptive, data-driven
alton every image, fact-checked if AI-written. - Important images belong in an image sitemap: see pseo-linking section 6.
- AI-generated images carry IPTC digital source type
TrainedAlgorithmicMediain the file metadata (Merchant Center requires it; see the research doc).
6. Configure Twitter Card Tags
Required Twitter tags:
twitter:card- Usually "summary_large_image"twitter:title- Can match OG titletwitter:description- Can match OG descriptiontwitter:image- Can match OG image
7. Add Supplementary Meta Tags
Where appropriate:
robots: Default toindex, follow; setnoindexonly for utility, filtered-view and share/tool-output pages; thin pages are not generated or return 404/410 (pseo-data, Data Sufficiency First)- Put
noindexin the initial HTML when you mean it, and do not rely on JavaScript to remove it later. If the original HTML hasnoindex, Google may skip rendering and never see the JS change (Google, 2025-12-15). Pages you may want indexed should not shipnoindexat all. - Do not use
noindexto save crawl budget; Google still requests the URL. Use 404/410 for removed pages and robots.txt for URL spaces you never want crawled. author: If content has an authorarticle:published_time/article:modified_time: For article-type pages
7a. Snippet and AI Feature Controls
Eligibility for AI Overviews and AI Mode needs only indexing and a snippet-eligible page. No extra tags are required. To limit use, per page:
nosnippet: no snippet in web search, Images, Discover, AI Overviews or AI Mode, and the content is not used as direct input for AI Overviews and AI Modemax-snippet:[n]: caps how much text may be used, including as direct input for AI Overviews and AI Modedata-nosnippet: excludes specific sections at text levelnoindex: removes the page from Search entirelynoarchive,nocache,nositelinkssearchboxare ignored
Site-wide, Search Console > Settings > Search generative AI can exclude the property from AI Overviews and AI Mode without affecting classic Search. Google-Extended in robots.txt does not control AI Overviews or AI Mode.
robots: { index: true, follow: true, "max-snippet": 160 } // only when you want a capGoogle respects robots meta tags in the body (2026-03-24), but still keep robots and canonical in the head.
7b. HTML Size
Keep head tags first and the HTML small. The 2MB Googlebot limit and how to stay under it: see pseo-templates section 6b.
8. Export Metadata in Page Files
Wire the metadata generator into every page route. In Next.js 16, params is a Promise:
// app/[category]/[slug]/page.tsx
import type { Metadata } from "next";
import { notFound } from "next/navigation";
export async function generateMetadata(
{ params }: { params: Promise<{ category: string; slug: string }> }
): Promise<Metadata> {
const { category, slug } = await params;
const data = await getPageData(slug);
if (!data || data.category !== category) notFound();
return generatePageMetadata(data, process.env.NEXT_PUBLIC_BASE_URL!);
}8a. Next.js 16 Metadata Streaming: Keep Canonical in the Head
Next.js may stream generateMetadata output into <body> for JavaScript-executing bots (verified for Googlebot). Google's canonical docs specify <head>, and there is no Google statement accepting rel=canonical in the body. To be safe:
- Make canonical and robots metadata resolve in the initial head shell: static metadata, a cached lookup (
"use cache"insidegenerateMetadataor the data function), or no runtime data in metadata. - With Cache Components, metadata that reads runtime data defers to request time. Next then forces an explicit choice:
use cacheingenerateMetadataor a dynamic marker. Choose the cache. - Or force blocking head metadata for all bots in
next.config.ts:
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
htmlLimitedBots: /.*/,
};
export default nextConfig;htmlLimitedBotsreplaces the default bot list, so the regex above must cover every bot you want to receive blocking metadata.- Verify with
curl -s URL | grep -i canonicaland check the tag appears inside<head>. This placement advice is an inference from Google's docs, not a Google guarantee.
9. Multilingual
See seo-i18n (hreflang only for published locales; sitemap hreflang preferred). Do not hardcode language lists in metadata.
Metadata Validation Rules
Run these checks (or integrate with pseo-quality-guard):
- No two pages produce the same title
- No two pages produce the same description
- All titles are between 30-70 characters
- All descriptions are between 100-170 characters
- All canonical URLs resolve to 200 status
- Canonical and robots tags appear inside
<head>in the raw HTML (curl, no JS) - Initial HTML is well under the 2MB limit (pseo-templates section 6b)
- All OG tags are present on every page
- No page is missing metadata entirely
File Organization
lib/
metadata.ts # generatePageMetadata() and helpers
metadata.test.ts # validation tests for metadata generationRelationship to Other Skills
- Depends on: pseo-data (content models provide metadata fields)
- Works with: pseo-templates (metadata is exported alongside page components)
- Validated by: pseo-quality-guard (checks uniqueness and completeness)
Verify
Build, start the app, and run seo-regression-guard against localhost (npx -y tsx <seo-regression-guard-dir>/scripts/seo-check.ts --site http://localhost:3000). Zero errors for the touched templates; canonical and robots appear inside <head> in the raw HTML.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

