skills/nuxt-seo-audit/SKILL.md
Use when auditing or setting up SEO for a Nuxt site. Triggers include missing page titles, no structured data, sitemap not including all pages, hreflang/canonical issues, pages not prerendered, trailing slash redirect loops, AI crawlers blocked in robots.txt, or preparing a site for search engine indexing.
npx skillsauth add razbakov/skills nuxt-seo-auditInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Full SEO audit for a Nuxt site. Check live responses, not just source code — what Google sees is what matters.
Run each check against the live deployed site using curl.
# Check every page type
for url in "/" "/about" "/blog" "/projects" "/cv"; do
title=$(curl -sL "https://example.com${url}" | grep -oP '(?<=<title>).*(?=</title>)')
echo "$url — $title"
done
What to check:
<title>titleTemplate set in nuxt.config.ts (e.g., %s · Site Name)curl -sL "https://example.com/about" | grep -oP '(?<=name="description" content=")[^"]*'
What to check:
useSeoMeta({ description })t('seo.pageDesc') not hardcoded English/de/about, /ru/blog, etc.curl -sL "https://example.com/about" | grep -oE '<meta property="og:[^"]*" content="[^"]*"'
What to check:
og:title — can differ from <title> (voice-first for social sharing)og:description — short, punchy versionog:image — set on every page (avatar for static, hero for blog posts)twitter:card — summary for static pages, summary_large_image for posts with imagescurl -sL "https://example.com/" | grep -oP '(?<=<script type="application/ld\+json">).*?(?=</script>)' | python3 -m json.tool
Required schema per page type:
| Page | Schema types |
|---|---|
| Home | WebSite, WebPage |
| About | AboutPage, Person (job, employer, languages, social links) |
| Blog index | CollectionPage, BreadcrumbList |
| Blog post | BlogPosting (headline, date, author, image), BreadcrumbList |
| Project index | WebPage, BreadcrumbList |
| Project detail | SoftwareApplication (name, url, author), BreadcrumbList |
Nuxt implementation: Use useSchemaOrg() with defineArticle, definePerson, defineBreadcrumb, defineSoftwareApp, defineWebSite, defineWebPage from nuxt-schema-org.
Validate at: Google Rich Results Test (search.google.com/test/rich-results)
curl -sL "https://example.com/sitemap_index.xml" | head -30
curl -sL "https://example.com/__sitemap__/en.xml" | grep -c "<url>"
What to check:
robots.txthreflang alternates// server/api/__sitemap__/urls.ts
import { serverQueryContent } from "#content/server";
import { defineSitemapEventHandler, asSitemapUrl } from "#imports";
export default defineSitemapEventHandler(async (e) => {
const content = await serverQueryContent(e).find();
return content
.filter((c) => c._path && !c._path.startsWith("/data/"))
.map((c) => asSitemapUrl({ loc: c._path, lastmod: c.date }));
});
curl -sL "https://example.com/robots.txt"
What to check:
Disallow on ClaudeBot, GPTBot, Google-Extended, Applebot-Extended. If blocked, content is invisible to AI search (Perplexity, ChatGPT, Google AI Overviews)for url in "/" "/about" "/de/about" "/blog"; do
echo "=== $url ==="
curl -sL "https://example.com${url}" | grep -oE '<link[^>]*(canonical|hreflang)[^>]*>'
echo
done
What to check:
<link rel="canonical">hreflang alternates for all languages + x-defaultNuxt i18n setup:
baseUrl in i18n config (required for hreflang generation)language property to each locale definitionuseLocaleHead doesn't work in app.vue during SSR, generate links manually based on route.pathfor url in "/" "/about" "/blog"; do
cache=$(curl -sI "https://example.com${url}" | grep -i "cache-control" | head -1)
code=$(curl -sI "https://example.com${url}" | head -1 | awk '{print $2}')
echo "$code $url — $cache"
done
What to check:
nuxt generate (not nuxt build) for full staticnitro.preset: "static" to prevent hosting platform SSR overridecache-control: public indicates static file servingcache-control or SSR-style headers means server-renderedNuxt config for static:
nitro: {
preset: "static",
prerender: {
crawlLinks: true,
routes: ["/", "/about", "/blog", "/projects"],
failOnError: false,
},
}
curl -sI "https://example.com/about" | grep -i "HTTP\|location"
What to check:
pretty_urls = false in netlify.toml to prevent trailing slash redirects_redirects file for legacy rules that conflict with current pagescat public/_redirects
What to check:
/about / when /about is a real page)## SEO Audit: [site URL]
| Check | Status | Issues |
|---|---|---|
| Page titles | Pass/Fail | ... |
| Meta descriptions | Pass/Fail | ... |
| OG tags | Pass/Fail | ... |
| Structured data | Pass/Fail | ... |
| Sitemap | Pass/Fail | ... |
| Robots.txt | Pass/Fail | ... |
| Hreflang/canonical | Pass/Fail | ... |
| Prerendering | Pass/Fail | ... |
| Trailing slashes | Pass/Fail | ... |
| Legacy redirects | Pass/Fail | ... |
### Issues Found
...
### Fixes Applied
...
t() keysbaseUrl in i18n config — hreflang tags won't generate without ituseLocaleHead in app.vue not reactive to route during SSR — may need manual link generationnuxt generate_redirects containing legacy rules that 301 away from real pagesfailOnError: true (default) failing build on broken internal linkstools
--- name: handoff description: Get an agent past a browser/UI wall it can't (or must not) cross on its own — a login-gated dashboard, a CAPTCHA, a 2FA prompt, an API that keeps rejecting the write, or an irreversible click that policy says a human must make. This skill is an ESCALATION LADDER, not a first move: it tells you to try the automated browser surfaces FIRST (Chrome-in-Claude, computer-use, an autonomous browser sub-agent) and only fall back to the Handoff app — a wrapper browser that h
documentation
Summarize one or more YouTube videos from their links. Use this whenever the user pastes a youtube.com or youtu.be URL (or several) and wants to know what it's about — phrasings like "summarize to telegram", "tldr these videos", "what do these say", "summary of this talk", or just dropping links with no instruction at all. Fetches each video's real transcript via yt-dlp (not the page text, which never contains the transcript), cleans the captions, and writes a per-video summary. Default delivery is Telegram; honor any other surface the user names ("to my notes", "just here in chat", "email it"). Trigger even when the user only pastes bare links — bare YouTube links almost always mean "tell me what's in these".
data-ai
Daily Digest — Chief-of-Staff role consolidates the six top-managers into one Telegram message to the Commander, instead of six. Implements the protocol from agent-proactivity.md.
development
Seed a new or empty Instagram account with a 9-post grid (3×3) so the profile looks established the moment a new visitor lands. Designed for festivals, new businesses, product launches, conferences, communities — any time an empty IG profile would hurt conversion from external traffic (QR scans, flyer drops, cross-promo). Generates assets via /image-from-gemini (per content-publishing rules — never HTML), writes captions with hashtag sets, and outputs a posting order + cadence plan. Trigger generously: phrases like '9 posts for instagram', 'fill my IG', 'starter grid', 'launch grid', 'instagram seed', '9-post grid', 'IG account not to look empty', 'first instagram posts', 'feed bootstrap', '3x3 grid', 'instagram launch content'. Even if the user mentions only one piece (just the images, just the captions, just the order), use this skill — the grid only works as an integrated bundle.