Loading...
Loading...
Create SEO-optimized pages at scale using programmatic/template-based approaches. Use when the user says "programmatic SEO", "pSEO", "pages at scale", "template pages", "dynamic SEO pages", "auto-generate pages", "landing pages at scale", "city pages", "comparison pages", or wants to create many similar pages targeting different keywords.
npx skill4agent add openclaudia/openclaudia-skills programmatic-seo{Modifier} + {Head Term} + {Qualifier}| Pattern Type | Formula | Example | Volume Potential |
|---|---|---|---|
| Location + Service | "{service} in {city}" | "plumber in Austin" | Cities x Services |
| Comparison | "{product A} vs {product B}" | "Notion vs Asana" | nC2 combinations |
| Integration | "{tool A} + {tool B} integration" | "Slack Salesforce integration" | Tools x Tools |
| Template/Example | "{type} template" | "invoice template" | Types count |
| Stats/Data | "{topic} statistics {year}" | "remote work statistics 2025" | Topics x Years |
| Glossary | "What is {term}" | "What is APR" | Terms count |
| Best/Top | "Best {product} for {use case}" | "Best CRM for startups" | Products x Uses |
| Review | "{product} review" | "Airtable review" | Products count |
| Alternative | "{product} alternatives" | "Slack alternatives" | Products count |
| Cost/Pricing | "How much does {service} cost" | "How much does a website cost" | Services count |
// Example: City + Service pages
interface PageData {
// URL parameters
slug: string; // "plumber-in-austin-tx"
city: string; // "Austin"
state: string; // "TX"
service: string; // "plumber"
// SEO fields
title: string; // "Best Plumber in Austin, TX | Top 10 for 2025"
metaDescription: string; // "Find the best plumber in Austin, TX..."
h1: string; // "Best Plumber in Austin, TX"
// Dynamic content
providers: Provider[]; // Local providers data
avgCost: number; // Average cost in this market
reviewCount: number; // Total reviews aggregated
faqs: FAQ[]; // Location-specific FAQs
// Related pages (internal linking)
nearbyPages: string[]; // Nearby cities
relatedServices: string[]; // Related services
}## Page Template: {Pattern Name}
### Above the Fold
- H1: {dynamic title}
- Key stat or hook: {dynamic data point}
- Quick summary: 2-3 sentences with unique data
- CTA (if commercial intent)
### Main Content Section 1: Overview
- {Entity}-specific introduction (NOT generic)
- Unique data point 1: {dynamic}
- Unique data point 2: {dynamic}
- Contextual explanation
### Main Content Section 2: Detailed Analysis
- Comparison table or detailed breakdown
- {Entity}-specific insights
- Data visualizations if applicable
### Main Content Section 3: Practical Information
- How-to or action steps
- Costs, timing, or specifications
- Location-specific or entity-specific details
### Related Content
- Internal links to related pages (same cluster)
- Links to parent/pillar page
- Links to sibling pages
### FAQ Section
- 3-5 questions specific to this entity
- Answers with unique data points
### Schema Markup
- Appropriate structured data for page type| Check | Requirement | How |
|---|---|---|
| Unique content | > 60% of visible text is unique to this page | Dynamic data, unique analysis, UGC |
| Sufficient depth | > 500 words of substantive content per page | Template sections + dynamic content |
| Unique data | At least 2 data points unique to this entity | API data, calculations, aggregations |
| Useful to visitor | Page answers the searcher's query fully | Match search intent |
| Not auto-generated feel | Reads naturally, not like a template | Varied sentence structures, context |
| Internal value | Links to and from other relevant pages | Related pages section, breadcrumbs |
| Visual content | At least 1 unique or relevant image | Maps, charts, entity images |
// app/[service]/[city]/page.tsx
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getPageData, getAllPages } from '@/lib/pseo-data';
interface Props {
params: { service: string; city: string };
}
// Generate static paths at build time
export async function generateStaticParams() {
const pages = await getAllPages();
return pages.map((page) => ({
service: page.serviceSlug,
city: page.citySlug,
}));
}
// Dynamic meta tags
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const data = await getPageData(params.service, params.city);
if (!data) return {};
return {
title: data.title,
description: data.metaDescription,
alternates: {
canonical: `https://example.com/${params.service}/${params.city}`,
},
openGraph: {
title: data.ogTitle,
description: data.ogDescription,
url: `https://example.com/${params.service}/${params.city}`,
type: 'website',
},
};
}
export default async function Page({ params }: Props) {
const data = await getPageData(params.service, params.city);
if (!data) notFound();
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'WebPage',
name: data.title,
description: data.metaDescription,
// ... additional schema
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* Page component tree */}
</>
);
}// app/sitemap.ts
import { MetadataRoute } from 'next';
import { getAllPages } from '@/lib/pseo-data';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const pages = await getAllPages();
return pages.map((page) => ({
url: `https://example.com/${page.serviceSlug}/${page.citySlug}`,
lastModified: page.updatedAt,
changeFrequency: 'monthly',
priority: 0.7,
}));
}// app/sitemap.xml/route.ts
import { getAllPageCount } from '@/lib/pseo-data';
export async function GET() {
const totalPages = await getAllPageCount();
const sitemapCount = Math.ceil(totalPages / 50000);
const sitemaps = Array.from({ length: sitemapCount }, (_, i) =>
`<sitemap><loc>https://example.com/sitemap-${i}.xml</loc></sitemap>`
).join('');
return new Response(
`<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${sitemaps}
</sitemapindex>`,
{ headers: { 'Content-Type': 'application/xml' } }
);
}// app/robots.ts
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/'],
},
],
sitemap: 'https://example.com/sitemap.xml',
};
}Hub: /services/plumber/
|- /plumber/austin-tx
|- /plumber/dallas-tx
|- /plumber/houston-txHome > Services > Plumber > Austin, TX// Internal linking component
function RelatedPages({ currentSlug, relatedPages }) {
return (
<section>
<h2>Related Pages</h2>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{relatedPages.map((page) => (
<Link
key={page.slug}
href={`/${page.slug}`}
className="text-blue-600 hover:underline"
>
{page.title}
</Link>
))}
</div>
</section>
);
}"{Primary Keyword} in {Location} | {Brand}"
"Best {Service} in {City}, {State} ({Year})"
"{Product A} vs {Product B}: {Differentiator}"
"{Number} Best {Category} for {Use Case} ({Year})"
"How Much Does {Service} Cost in {City}? ({Year} Pricing)""Find the best {service} in {city}. Compare {X} local providers, read {Y} reviews, and get free quotes. Average cost: ${Z}."
"Detailed comparison of {A} vs {B}. See features, pricing, pros/cons, and which is better for {use case}."
"{X} best {category} for {audience}. We analyzed {Y} options based on {criteria}. Updated for {year}.""Best {Service} in {City}, {State}"
"{Product A} vs {Product B}: Complete Comparison"
"{Number} Best {Category} for {Use Case}"noindex