name: website-launchpad-seo version: v2 description: > SEO specification for website-launchpad. Trigger when building or modifying any page, adding metadata, configuring schema, setting up analytics, or working on anything that affects search engine visibility. Always read this alongside design-system/SKILL.md before generating any page code.
SEO Skill — v2
Based on PingCAP SEO Audit (February 2026). Every rule in this skill derives from the audit findings.
File Index — Read Based on Your Task
| File | When to Read |
|---|---|
audit-rules.md |
Required for every page — 10 cross-stack rules + compliance status |
audit-page-types.md |
Required for every page — schema, metadata, GTM spec per page type |
seo.md |
Detailed metadata, image SEO, Core Web Vitals, URL rules |
Quick Checklist (run before outputting any page)
Metadata
-
metadataexport withtitle,description,openGraph,twitter,robots,canonical -
siteName: 'TiDB'— exact string, no variations -
twitter.site: '@PingCAP'— exact string -
openGraph.imagespresent — defaulthttps://static.pingcap.com/files/2024/09/11005522/Homepage-Ad.png; replace with page-specific OG image when available -
twitter.imagespresent — same default URL (format: array of strings['url']) -
canonicalalwayshttps://www.pingcap.com/[path]/— neververcel.app - Landing pages (
/lp/*):robots: { index: false, follow: false }
Schema
- Always use
buildPageSchema()from@/lib/schema— never standalone JSON-LD - Correct extra schema for page type (see
audit-page-types.md) - Glossary index →
glossaryIndexSchema() - Glossary term →
definedTermSchema() - Product page →
softwareApplicationSchema() - SEO content page →
articleSchema() - Compare page →
faqSchema()
Analytics
- Import tracking helpers from
@/lib/gtm— never rawdataLayer.push() - Correct
page_typefor the path (seeaudit-page-types.md)
Sitemap
- New page added to
src/app/sitemap.ts
HTML
- Exactly one
<h1>per page - Heading hierarchy: h1 → h2 → h3, no skipped levels
- All
<Image>have descriptivealttext -
priorityon above-the-fold images - WordPress cross-links use
<a href>, not<Link>
URL
- Lowercase, hyphen-separated, trailing slash
Schema Usage Reference
import {
buildPageSchema,
softwareApplicationSchema,
articleSchema,
faqSchema,
definedTermSchema,
glossaryIndexSchema,
} from '@/lib/schema'
// Every page — base structure
const schema = buildPageSchema({
path: '/glossary/',
title: '...',
description: '...',
pageType: 'CollectionPage',
breadcrumbs: [
{ name: 'Home', path: '/' },
{ name: 'Glossary', path: '/glossary/' },
],
extraSchemas: [glossaryIndexSchema({ termCount: 42 })],
})
GTM Usage Reference
File: src/lib/gtm.tsx (note: .tsx extension, not .ts)
Available exports: trackCTAClick, trackFormSubmit, trackPageView, pushEvent, GTMScript, GTMNoScript, PageType
Runtime rule:
- GTM scripts load only when
process.env.VERCEL_ENV === 'production'. - Vercel Preview deployments (
VERCEL_ENV=preview) should not load GTM containers.
import { trackCTAClick, trackFormSubmit } from '@/lib/gtm'
// CTA button click
trackCTAClick({ cta_text: 'Start for Free', cta_location: 'hero', page_path: '/glossary/' })
// Form submit
trackFormSubmit({ form_id: 'hubspot-contact', page_path: '/contact/' })
// page_view fires automatically via RouteTracker in layout.tsx — no manual call needed