Technical SEO audit and implementation: structured data (JSON-LD), meta tags, Open Graph/Twitter Cards, XML sitemap, robots.txt, Core Web Vitals optimization, crawl budget management, and canonical URL strategy.
From sovereign-architectnpx claudepluginhub javimontano/mao-sovereign-architectThis skill is limited to using the following tools:
agents/seo-technical-agent.mdagents/structured-data-agent.mdevals/evals.jsonexamples/sample-output.mdprompts/use-case-prompts.mdreferences/body-of-knowledge.mdreferences/knowledge-graph.mmdreferences/state-of-the-art.md"Technical SEO is the foundation. No amount of content or links helps if Googlebot can't parse, render, or index your pages correctly."
Five-step procedure to audit and implement technical SEO: metadata architecture, structured data for rich results, sitemap and robots.txt configuration, Core Web Vitals as ranking signals, and crawl budget management for large sites.
robots.txt — verify no accidental Disallow: / rules blocking prod.<meta name="robots"> on key pages — confirm no noindex leaking from staging.curl -I https://domain.com/page — check for redirects, X-Robots-Tag headers.robots.txt PatternUser-agent: *
Allow: /
# Block parameterized facets that don't add indexable value
Disallow: /search?*
Disallow: /products?sort=*
Disallow: /products?page=*
# Block admin, API, auth
Disallow: /admin/
Disallow: /api/
Disallow: /_next/
Sitemap: https://www.example.com/sitemap.xml
Sitemap: https://www.example.com/sitemap-blog.xml
// app/layout.tsx — root metadata
import { Metadata } from 'next';
export const metadata: Metadata = {
metadataBase: new URL('https://www.example.com'),
title: {
default: 'Company Name — Value Proposition',
template: '%s | Company Name',
},
description: 'Under 160 characters. Imperative, specific, keyword-rich.',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
alternates: {
canonical: 'https://www.example.com',
languages: {
'en-US': 'https://www.example.com',
'es-MX': 'https://es.example.com',
},
},
};
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
type: 'article',
title: post.title,
description: post.excerpt,
url: `https://www.example.com/blog/${post.slug}`,
images: [{ url: post.ogImage, width: 1200, height: 630, alt: post.title }],
publishedTime: post.publishedAt,
modifiedTime: post.updatedAt,
authors: [post.author.url],
},
twitter: {
card: 'summary_large_image',
title: post.title,
description: post.excerpt,
images: [post.ogImage],
creator: '@handle',
},
};
}
// components/StructuredData.tsx
export function OrganizationSchema() {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Example Company',
url: 'https://www.example.com',
logo: 'https://www.example.com/logo.png',
sameAs: [
'https://www.linkedin.com/company/example',
'https://twitter.com/example',
],
}),
}}
/>
);
}
export function ArticleSchema({ post }: { post: Post }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
description: post.excerpt,
image: post.ogImage,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: { '@type': 'Person', name: post.author.name, url: post.author.url },
publisher: {
'@type': 'Organization',
name: 'Example Company',
logo: { '@type': 'ImageObject', url: 'https://www.example.com/logo.png' },
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://www.example.com/blog/${post.slug}`,
},
}),
}}
/>
);
}
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "How does X work?",
"acceptedAnswer": {
"@type": "Answer",
"text": "X works by... [full answer, not truncated]"
}
}
]
}
// app/sitemap.ts — Next.js dynamic sitemap
import { MetadataRoute } from 'next';
import { getAllPosts, getAllProducts } from '@/lib/api';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const [posts, products] = await Promise.all([getAllPosts(), getAllProducts()]);
const staticPages: MetadataRoute.Sitemap = [
{ url: 'https://www.example.com', lastModified: new Date(), changeFrequency: 'daily', priority: 1.0 },
{ url: 'https://www.example.com/about', changeFrequency: 'monthly', priority: 0.8 },
{ url: 'https://www.example.com/blog', changeFrequency: 'daily', priority: 0.9 },
];
const postPages: MetadataRoute.Sitemap = posts.map((post) => ({
url: `https://www.example.com/blog/${post.slug}`,
lastModified: new Date(post.updatedAt),
changeFrequency: 'weekly',
priority: 0.7,
}));
return [...staticPages, ...postPages];
}
// Preload hero image — most impactful LCP fix
// Next.js Image with priority:
<Image src="/hero.webp" alt="..." width={1200} height={630} priority />
// Generates: <link rel="preload" as="image" fetchpriority="high" />
/* Always set explicit dimensions on images and embeds */
img { width: 100%; height: auto; aspect-ratio: attr(width) / attr(height); }
/* Reserve space for dynamic content — fonts */
@font-face {
font-display: swap; /* Prevents invisible text during font load */
}
// Defer non-critical JS
<Script src="/analytics.js" strategy="lazyOnload" />
// Yield to browser for long tasks
async function processLargeList(items: Item[]) {
for (const item of items) {
processItem(item);
// yield every 50ms to allow browser to handle input
if (performance.now() % 50 < 1) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}
# Lighthouse CI in GitHub Actions
npx lhci autorun \
--collect.url=https://example.com \
--upload.target=temporary-public-storage
# PageSpeed Insights API
curl "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://example.com&strategy=mobile&key=$PSI_API_KEY" \
| jq '.lighthouseResult.categories.performance.score'
<title> and <meta description> — No duplicates, under 60/160 chars.fetchPriority="high".noindex on production pages — Staging noindex not leaked to prod.<title> tag in <body> — Some frameworks accidentally render it outside <head>; crawlers may ignore it.loading="lazy" on the above-the-fold hero image delays LCP by 200-500ms.@import in stylesheets — Each @import is a serial round trip; use <link> tags or bundler.<head>.robots.txt blocking JS/CSS — Googlebot cannot render pages if core assets are disallowed; renders mobile-unfriendly.Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.