Not in the top 1,000 by GitHub stars
Imam-Abubakar/ultimate-seo
A Claude skill that gives any web project a production-grade SEO setup, then hands you a playbook for everything else.
History
Review weekly changes to SKILL.md before updating. Dates mark the weeks in which we observed each version; checks apply to the recorded commits.
View weekly changes
skills/ultimate-seo/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
499c21e45def → 499c21e45def
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 499c21e45def
No earlier version was observed for comparison.
Verified commit 499c21e45defd888c847525090daf57ff47325e1
git clone --filter=blob:none --no-checkout https://github.com/Imam-Abubakar/ultimate-seo.git .hotskills/imam-abubakar-ultimate-seo && git -C .hotskills/imam-abubakar-ultimate-seo checkout --detach 499c21e45defd888c847525090daf57ff47325e1
# Copy each selected skill directory from .hotskills/imam-abubakar-ultimate-seo into .claude/skills/<skill-name>/Heat
1.3- Star growth, last 7 daysNot available
- Star growth, last 24 hoursNot available
- Rank movement, last 7 daysNot available
- Commits, last 30 daysNot available
- Accounts asking about it through MCP, last 7 daysNot available
- Hot votes this weekNot available
Heat never changes the order by stars, and sponsorship never touches it. How heat works
Stars over time
30-day change not yet available: not enough history.
Individual skills in this repository
- ultimate-seo
skills/ultimate-seo
How it works
ultimate-seo
When your agent uses it
Implements a complete, production-grade SEO setup in any web project (Next.js, React/Vite SPAs, Remix/React Router, Astro, Nuxt/Vue, SvelteKit, Gatsby, Angular, plain HTML, Hugo/Jekyll/Eleventy, Django/Rails/Laravel, WordPress/Shopify) and writes an ULTIMATE-SEO.md playbook of the remaining human steps. Covers metadata, canonicals, robots.txt, sitemaps, Open Graph/social cards, JSON-LD structured data, Core Web Vitals, hreflang, AI-search readiness (llms.txt, AI crawler policy) and an audit script. Use this whenever the user wants to improve SEO, rank on Google, fix indexing, add meta tags, sitemaps, robots.txt, OG images or schema markup, prep a site for launch, audit a site's search readiness, or asks why their site is not showing up in search or AI answers, even if they never say the word SEO.
What it loads into context
Frontmatter
226 tokensAlways available to the agent
SKILL.md
4,006 tokensWhen the skill is activated
Reference documents
83,251 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Workflow
- Scope variations
- Things that look like SEO but hurt
- Reference map
Scripts executed separately
evals/audit-only-no-code-changes/files/astro.config.mjsevals/audit-only-no-code-changes/files/package.jsonevals/audit-only-no-code-changes/place-files.shevals/nextjs-blog-full-setup/files/app/about/page.tsxevals/nextjs-blog-full-setup/files/app/blog/[slug]/page.tsxevals/nextjs-blog-full-setup/files/app/blog/page.tsxevals/nextjs-blog-full-setup/files/app/layout.tsxevals/nextjs-blog-full-setup/files/app/page.tsxevals/nextjs-blog-full-setup/files/lib/posts.tsevals/nextjs-blog-full-setup/files/package.jsonevals/nextjs-blog-full-setup/place-files.shevals/static-html-local-bakery/place-files.shevals/vite-react-spa-landing/files/package.jsonevals/vite-react-spa-landing/files/src/App.tsxevals/vite-react-spa-landing/files/src/main.tsxevals/vite-react-spa-landing/files/src/pages/About.tsxevals/vite-react-spa-landing/files/src/pages/Features.tsxevals/vite-react-spa-landing/files/src/pages/Home.tsxevals/vite-react-spa-landing/files/src/pages/Pricing.tsxevals/vite-react-spa-landing/files/vite.config.tsevals/vite-react-spa-landing/place-files.shscripts/detect_stack.pyscripts/generate_sitemap.pyscripts/seo_audit.pyscripts/seo_lib.pyscripts/validate_jsonld.py
Files
../../.claude-plugin/marketplace.jsonasset437 bytes../../.claude-plugin/plugin.jsonasset469 bytesSKILL.mdcore16,723 bytesSKILL.mdcore16,723 bytesSKILL.mdcore16,723 bytesSKILL.mdcore16,723 bytesSKILL.mdcore16,723 bytesassets/ULTIMATE-SEO.template.mddoc7,432 bytesassets/jsonld/article.jsonasset687 bytesassets/jsonld/breadcrumb.jsonasset436 bytesassets/jsonld/event.jsonasset1,022 bytesassets/jsonld/faq.jsonasset459 bytesassets/jsonld/local-business.jsonasset1,118 bytesassets/jsonld/organization-website.jsonasset1,025 bytesassets/jsonld/person-profile.jsonasset490 bytesassets/jsonld/product.jsonasset1,934 bytesassets/jsonld/software-application.jsonasset576 bytesassets/jsonld/video.jsonasset400 bytesassets/llms.txtdoc1,049 bytesassets/robots.txtdoc1,311 bytesevals/audit-only-no-code-changes/case.yamlasset501 bytesevals/audit-only-no-code-changes/files/astro.config.mjsruns79 bytesevals/audit-only-no-code-changes/files/package.jsonruns221 bytesevals/audit-only-no-code-changes/files/public/robots.txtdoc26 bytesevals/audit-only-no-code-changes/files/src/layouts/Docs.astroasset285 bytesevals/audit-only-no-code-changes/files/src/pages/api.astroasset195 bytesevals/audit-only-no-code-changes/files/src/pages/getting-started.astroasset179 bytesevals/audit-only-no-code-changes/files/src/pages/index.astroasset214 bytesevals/audit-only-no-code-changes/graders/01-no-source-changes.mddoc191 bytesevals/audit-only-no-code-changes/graders/02-detects-astro.mddoc211 bytesevals/audit-only-no-code-changes/graders/03-names-concrete-problems.mddoc262 bytesevals/audit-only-no-code-changes/graders/04-prioritized.mddoc199 bytesevals/audit-only-no-code-changes/graders/05-flags-robots-block-all.mddoc183 bytesevals/audit-only-no-code-changes/place-files.shruns62 bytesevals/audit-only-no-code-changes/prompt.mddoc484 bytesevals/nextjs-blog-full-setup/case.yamlasset459 bytesevals/nextjs-blog-full-setup/files/README.mddoc44 bytesevals/nextjs-blog-full-setup/files/app/about/page.tsxruns223 bytesevals/nextjs-blog-full-setup/files/app/blog/[slug]/page.tsxruns560 bytesevals/nextjs-blog-full-setup/files/app/blog/page.tsxruns358 bytesevals/nextjs-blog-full-setup/files/app/layout.tsxruns370 bytesevals/nextjs-blog-full-setup/files/app/page.tsxruns407 bytesevals/nextjs-blog-full-setup/files/lib/posts.tsruns1,074 bytesevals/nextjs-blog-full-setup/files/package.jsonruns342 bytesevals/nextjs-blog-full-setup/files/public/covers/.gitkeepasset0 bytesevals/nextjs-blog-full-setup/files/tsconfig.jsonasset639 bytesevals/nextjs-blog-full-setup/graders/01-metadata-base-and-template.mddoc207 bytesevals/nextjs-blog-full-setup/graders/02-post-generate-metadata.mddoc207 bytesevals/nextjs-blog-full-setup/graders/03-robots-and-sitemap.mddoc207 bytesevals/nextjs-blog-full-setup/graders/04-jsonld.mddoc213 bytesevals/nextjs-blog-full-setup/graders/05-no-invented-facts.mddoc234 bytesevals/nextjs-blog-full-setup/graders/06-playbook-exists-and-specific.mddoc255 bytesevals/nextjs-blog-full-setup/graders/07-build-attempted.mddoc225 bytesevals/nextjs-blog-full-setup/place-files.shruns62 bytesevals/nextjs-blog-full-setup/prompt.mddoc501 bytesevals/static-html-local-bakery/case.yamlasset482 bytesevals/static-html-local-bakery/files/contact.htmlasset411 bytesevals/static-html-local-bakery/files/images/README.txtdoc78 bytesevals/static-html-local-bakery/files/index.htmlasset598 bytesevals/static-html-local-bakery/files/menu.htmlasset538 bytesevals/static-html-local-bakery/files/style.cssasset102 bytesevals/static-html-local-bakery/graders/01-unique-heads.mddoc258 bytesevals/static-html-local-bakery/graders/02-localbusiness-schema-accurate.mddoc343 bytesevals/static-html-local-bakery/graders/03-robots-and-sitemap.mddoc186 bytesevals/static-html-local-bakery/graders/04-images-and-headings.mddoc135 bytesevals/static-html-local-bakery/graders/05-local-playbook.mddoc285 bytesevals/static-html-local-bakery/place-files.shruns62 bytesevals/static-html-local-bakery/prompt.mddoc490 bytesevals/vite-react-spa-landing/case.yamlasset571 bytesevals/vite-react-spa-landing/files/index.htmlasset360 bytesevals/vite-react-spa-landing/files/package.jsonruns457 bytesevals/vite-react-spa-landing/files/public/favicon.svgasset119 bytesevals/vite-react-spa-landing/files/src/App.tsxruns791 bytesevals/vite-react-spa-landing/files/src/main.tsxruns301 bytesevals/vite-react-spa-landing/files/src/pages/About.tsxruns205 bytesevals/vite-react-spa-landing/files/src/pages/Features.tsxruns361 bytesevals/vite-react-spa-landing/files/src/pages/Home.tsxruns318 bytesevals/vite-react-spa-landing/files/src/pages/Pricing.tsxruns232 bytesevals/vite-react-spa-landing/files/tsconfig.jsonasset233 bytesevals/vite-react-spa-landing/files/vite.config.tsruns133 bytesevals/vite-react-spa-landing/graders/01-diagnoses-spa-shell.mddoc226 bytesevals/vite-react-spa-landing/graders/02-prerender-or-ssr.mddoc278 bytesevals/vite-react-spa-landing/graders/03-per-route-metadata.mddoc203 bytesevals/vite-react-spa-landing/graders/04-robots-sitemap-public.mddoc199 bytesevals/vite-react-spa-landing/graders/05-no-fake-ratings.mddoc144 bytesevals/vite-react-spa-landing/graders/06-playbook.mddoc208 bytesevals/vite-react-spa-landing/place-files.shruns62 bytesevals/vite-react-spa-landing/prompt.mddoc676 bytesreferences/ai-search.mddoc14,097 bytesreferences/content-strategy.mddoc16,954 bytesreferences/ecommerce.mddoc14,900 bytesreferences/frameworks/angular.mddoc9,550 bytesreferences/frameworks/astro.mddoc11,803 bytesreferences/frameworks/cms-platforms.mddoc12,856 bytesreferences/frameworks/gatsby.mddoc9,007 bytesreferences/frameworks/nextjs-app-router.mddoc16,064 bytesreferences/frameworks/nextjs-pages-router.mddoc12,398 bytesreferences/frameworks/nuxt-vue.mddoc11,143 bytesreferences/frameworks/react-router-remix.mddoc11,099 bytesreferences/frameworks/react-spa.mddoc13,174 bytesreferences/frameworks/server-rendered.mddoc16,220 bytesreferences/frameworks/static-html.mddoc10,055 bytesreferences/frameworks/static-site-generators.mddoc12,794 bytesreferences/frameworks/sveltekit.mddoc10,485 bytesreferences/international.mddoc12,791 bytesreferences/launch-and-monitoring.mddoc14,524 bytesreferences/local-seo.mddoc12,918 bytesreferences/metadata.mddoc14,071 bytesreferences/performance.mddoc12,648 bytesreferences/structured-data.mddoc20,997 bytesreferences/technical-seo.mddoc15,824 bytesscripts/detect_stack.pyruns22,470 bytesscripts/generate_sitemap.pyruns6,643 bytesscripts/seo_audit.pyruns31,195 bytesscripts/seo_lib.pyruns12,462 bytesscripts/validate_jsonld.pyruns14,750 bytes
Read SKILL.md
# Ultimate SEO
You are acting as a senior technical SEO engineer who is also a strong developer in whatever stack this project uses. The goal is twofold:
1. **Ship the setup.** Implement everything that can be done in code, idiomatically for this stack, so the site is crawlable, indexable, richly previewed, fast, and understandable to both search engines and AI answer engines.
2. **Hand over the playbook.** Write `ULTIMATE-SEO.md` at the project root: what you did, what only a human can do (verify Search Console, write content, earn links...), and a prioritized roadmap to take the site to the top.
A great result is one where the user's next deploy is measurably better and they know exactly what to do next. A bad result is a pile of generic tags pasted into the wrong place, invented business facts, or a broken build.
## Workflow
Work through these phases in order. Keep the user informed with short progress notes, but don't stop to ask permission for things this skill already tells you to do.
### Phase 1 — Detect the stackView the complete source on GitHubSkills included
- ultimate-seo
Repository facts
- License
- MIT
- Created
- Oct 28, 2026
- Last pushed
- Oct 28, 2026
- Forks
- 0
- Open issues
- 0
- Project activity
- Active
Before you install
Network or broad shellAutomated signals, not a guarantee
Checked Nov 4, 2026
Not fully analyzed: some files were too long, unreadable or missing. This never lowers the level.
Show 4 notes
skills/ultimate-seo/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedskills/ultimate-seo/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedskills/ultimate-seo/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedskills/ultimate-seo/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed
- No broad tool permissions
- No dangerous shell commands
- 673 network referencesin 48 files: ultimate-seo/references/structured-data.md:51 ultimate-seo/references/ecommerce.md:57 ultimate-seo/references/frameworks/static-html.md:49 and 45 more
- No hidden or obfuscated text
- No instruction overrides
- 1 reference to secretsin 1 file: ultimate-seo/references/frameworks/server-rendered.md:48
- No requests to vote in Hot
Show all 700 signals by file
skills/ultimate-seo/SKILL.md
- Network accessline 38
- **Canonical origin** — the production URL (`https://www.example.com`). Look in env files, deploy configs (`vercel.json`, `netlify.toml`, `CNAME`, `wrangler.toml`), README, existing metadata. - Network accessline 50
- **Built output** (best for static/SSG): build the project, then `python3 <skill-dir>/scripts/seo_audit.py <build-dir>` (e.g. `dist`, `out`, `build`, `.output/public`, `public`, `_site`). - **Running server** (best for SSR/SPAs): start the - Network accessline 51
- **Running server** (best for SSR/SPAs): start the dev or preview server and run `python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50`. The audit fetches raw HTML without executing JavaScript, which is exactly what so - Network accessline 90
2. Re-run `seo_audit.py` the same way as the baseline and compare the score and issue list. 3. Validate JSON-LD: `python3 <skill-dir>/scripts/validate_jsonld.py <build-dir-or-url-or-file>`. 4. Spot-check the rendered HTML of the home page a - Network accessline 91
3. Validate JSON-LD: `python3 <skill-dir>/scripts/validate_jsonld.py <build-dir-or-url-or-file>`. 4. Spot-check the rendered HTML of the home page and one dynamic page (`curl -s URL | head -80` or open the built file): title, description, c - Network accessline 92
4. Spot-check the rendered HTML of the home page and one dynamic page (`curl -s URL | head -80` or open the built file): title, description, canonical, OG tags, JSON-LD present and absolute URLs correct. - Network accessline 117
- **"Just audit my site"** — run phases 1–3 without changing code, then write `ULTIMATE-SEO.md` in audit form: replace *Scorecard*'s before/after with the current score, turn *What was implemented* into *What's wrong* (each finding with its - Network accessline 118
- **A single concern** ("add a sitemap", "fix OG images") — do that thing excellently using the relevant reference, check its neighbours (a sitemap is useless if robots blocks the URLs), and skip the full playbook unless asked; mention the - Network accessline 119
- **Live URL with no repo** — run `seo_audit.py https://site --crawl 100` and `validate_jsonld.py https://site`, then produce `ULTIMATE-SEO.md` as an audit + roadmap.
skills/ultimate-seo/assets/ULTIMATE-SEO.template.md
- Network accessline 14
> Generated by the ultimate-seo Claude skill on {{YYYY-MM-DD}} for `{{https://www.example.com}}` ({{framework + version}}, {{rendering mode}}). - Network accessline 58
| What | Where | Current value | |---|---|---| | Production origin | `{{.env.production → NEXT_PUBLIC_SITE_URL}}` | {{`https://www.example.com` (placeholder)}} | - Network accessline 59
|---|---|---| | Production origin | `{{.env.production → NEXT_PUBLIC_SITE_URL}}` | {{`https://www.example.com` (placeholder)}} | | Social profiles for `sameAs` | `{{src/config/site.ts}}` | {{empty}} | - Network accessline 60
| Production origin | `{{.env.production → NEXT_PUBLIC_SITE_URL}}` | {{`https://www.example.com` (placeholder)}} | - Network accessline 73
- [ ] **Google Search Console** — add a *Domain* property for `{{example.com}}` (DNS TXT record), then submit `{{https://www.example.com/sitemap.xml}}` under *Sitemaps*. - Network accessline 74
- [ ] **Bing Webmaster Tools** — import the site from Search Console (one click); submit the sitemap. Bing also feeds Copilot and other AI search tools. - [ ] **Redirects** — make sure `{{http://}}` and `{{apex/www variant}}` 301 to `{{http - Network accessline 75
- [ ] **Redirects** — make sure `{{http://}}` and `{{apex/www variant}}` 301 to `{{https://www.example.com}}` at the host/CDN ({{Vercel → Domains}}). - Network accessline 76
- [ ] **Validate** — run 3 key URLs through the [Rich Results Test](https://search.google.com/test/rich-results) and [PageSpeed Insights](https://pagespeed.web.dev/) after deploy.
skills/ultimate-seo/assets/jsonld/article.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 3
"@type": "BlogPosting", "@id": "https://www.example.com/blog/post-slug/#article", "mainEntityOfPage": "https://www.example.com/blog/post-slug/", - Network accessline 4
"@id": "https://www.example.com/blog/post-slug/#article", - Network accessline 5
"mainEntityOfPage": "https://www.example.com/blog/post-slug/", - Network accessline 7
"description": "The post's meta description.", "image": [ "https://www.example.com/blog/post-slug/cover-1200x675.jpg" - Network accessline 8
"image": [ "https://www.example.com/blog/post-slug/cover-1200x675.jpg" ], - Network accessline 9
"https://www.example.com/blog/post-slug/cover-1200x675.jpg" - Network accessline 14
"@type": "Person", "name": "Author Name", "url": "https://www.example.com/authors/author-name/" - Network accessline 15
"name": "Author Name", "url": "https://www.example.com/authors/author-name/" }, - Network accessline 16
"url": "https://www.example.com/authors/author-name/" - Network accessline 17
}, "publisher": { "@id": "https://www.example.com/#organization" - Network accessline 18
"publisher": { "@id": "https://www.example.com/#organization" }, - Network accessline 19
"@id": "https://www.example.com/#organization"
skills/ultimate-seo/assets/jsonld/breadcrumb.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 7
"position": 1, "name": "Home", "item": "https://www.example.com/" - Network accessline 8
"name": "Home", "item": "https://www.example.com/" }, - Network accessline 9
"item": "https://www.example.com/" - Network accessline 13
"position": 2, "name": "Blog", "item": "https://www.example.com/blog/" - Network accessline 14
"name": "Blog", "item": "https://www.example.com/blog/" }, - Network accessline 15
"item": "https://www.example.com/blog/"
skills/ultimate-seo/assets/jsonld/event.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 6
"startDate": "2026-11-20T18:00:00-05:00", "endDate": "2026-11-20T21:00:00-05:00", "eventStatus": "https://schema.org/EventScheduled", - Network accessline 7
"endDate": "2026-11-20T21:00:00-05:00", "eventStatus": "https://schema.org/EventScheduled", "eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode", - Network accessline 8
"eventStatus": "https://schema.org/EventScheduled", - Network accessline 9
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode", - Network accessline 20
}, "image": [ "https://www.example.com/events/event-cover.jpg" - Network accessline 21
"image": [ "https://www.example.com/events/event-cover.jpg" ], - Network accessline 22
"https://www.example.com/events/event-cover.jpg" - Network accessline 24
"offers": { "@type": "Offer", "url": "https://www.example.com/events/event-slug/", - Network accessline 25
"@type": "Offer", "url": "https://www.example.com/events/event-slug/", "price": "25.00", - Network accessline 26
"url": "https://www.example.com/events/event-slug/", - Network accessline 27
"price": "25.00", "priceCurrency": "USD", "availability": "https://schema.org/InStock", - Network accessline 28
"priceCurrency": "USD", "availability": "https://schema.org/InStock", "validFrom": "2026-09-01T00:00:00-05:00" - Network accessline 29
"availability": "https://schema.org/InStock", - Network accessline 33
"@type": "Organization", "name": "Example Brand", "url": "https://www.example.com/" - Network accessline 34
"name": "Example Brand", "url": "https://www.example.com/" } - Network accessline 35
"url": "https://www.example.com/"
skills/ultimate-seo/assets/jsonld/faq.json
skills/ultimate-seo/assets/jsonld/local-business.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 3
"@type": "LocalBusiness", "@id": "https://www.example.com/#business", "name": "Business name", - Network accessline 4
"@id": "https://www.example.com/#business", - Network accessline 5
"name": "Business name", "url": "https://www.example.com/", "image": "https://www.example.com/images/storefront.jpg", - Network accessline 6
"url": "https://www.example.com/", - Network accessline 7
"image": "https://www.example.com/images/storefront.jpg", - Network accessline 31
], "sameAs": [ "https://www.facebook.com/example", - Network accessline 32
"sameAs": [ "https://www.facebook.com/example", "https://www.instagram.com/example" - Network accessline 33
"https://www.facebook.com/example", - Network accessline 34
"https://www.instagram.com/example"
skills/ultimate-seo/assets/jsonld/organization-website.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 4
{ "@type": "Organization", "@id": "https://www.example.com/#organization", - Network accessline 5
"@type": "Organization", "@id": "https://www.example.com/#organization", "name": "Example Brand", - Network accessline 6
"@id": "https://www.example.com/#organization", - Network accessline 7
"name": "Example Brand", "url": "https://www.example.com/", "logo": { - Network accessline 8
"url": "https://www.example.com/", - Network accessline 9
"logo": { "@type": "ImageObject", "url": "https://www.example.com/logo-512.png", - Network accessline 10
"@type": "ImageObject", "url": "https://www.example.com/logo-512.png", "width": 512, - Network accessline 11
"url": "https://www.example.com/logo-512.png", - Network accessline 15
"description": "One sentence describing what the organization does.", "sameAs": [ "https://www.linkedin.com/company/example", - Network accessline 16
"sameAs": [ "https://www.linkedin.com/company/example", "https://github.com/example", - Network accessline 17
"https://www.linkedin.com/company/example", - Network accessline 18
"https://github.com/example", - Network accessline 19
"https://x.com/example" - Network accessline 27
{ "@type": "WebSite", "@id": "https://www.example.com/#website", - Network accessline 28
"@type": "WebSite", "@id": "https://www.example.com/#website", "name": "Example Brand", - Network accessline 29
"@id": "https://www.example.com/#website", - Network accessline 30
"name": "Example Brand", "url": "https://www.example.com/", "inLanguage": "en", - Network accessline 31
"url": "https://www.example.com/", - Network accessline 32
"inLanguage": "en", "publisher": { "@id": "https://www.example.com/#organization" - Network accessline 33
"publisher": { "@id": "https://www.example.com/#organization" } - Network accessline 34
"@id": "https://www.example.com/#organization"
skills/ultimate-seo/assets/jsonld/person-profile.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 5
"mainEntity": { "@type": "Person", "@id": "https://www.example.com/#person", - Network accessline 6
"@type": "Person", "@id": "https://www.example.com/#person", "name": "Full Name", - Network accessline 7
"@id": "https://www.example.com/#person", - Network accessline 8
"name": "Full Name", "url": "https://www.example.com/", "jobTitle": "Role", - Network accessline 9
"url": "https://www.example.com/", - Network accessline 10
"jobTitle": "Role", "image": "https://www.example.com/images/headshot.jpg", "description": "One-line bio.", - Network accessline 11
"image": "https://www.example.com/images/headshot.jpg", - Network accessline 12
"description": "One-line bio.", "sameAs": [ "https://www.linkedin.com/in/example", - Network accessline 13
"sameAs": [ "https://www.linkedin.com/in/example", "https://github.com/example" - Network accessline 14
"https://www.linkedin.com/in/example", - Network accessline 15
"https://github.com/example"
skills/ultimate-seo/assets/jsonld/product.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 3
"@type": "Product", "@id": "https://www.example.com/products/sku-123/#product", "name": "Product name", - Network accessline 4
"@id": "https://www.example.com/products/sku-123/#product", - Network accessline 6
"description": "Product description as shown on the page.", "image": [ "https://www.example.com/images/sku-123-1x1.jpg", - Network accessline 7
"image": [ "https://www.example.com/images/sku-123-1x1.jpg", "https://www.example.com/images/sku-123-4x3.jpg", - Network accessline 8
"https://www.example.com/images/sku-123-1x1.jpg", - Network accessline 9
"https://www.example.com/images/sku-123-4x3.jpg", - Network accessline 10
"https://www.example.com/images/sku-123-16x9.jpg" - Network accessline 18
"offers": { "@type": "Offer", "url": "https://www.example.com/products/sku-123/", - Network accessline 19
"@type": "Offer", "url": "https://www.example.com/products/sku-123/", "price": "49.00", - Network accessline 20
"url": "https://www.example.com/products/sku-123/", - Network accessline 21
"price": "49.00", "priceCurrency": "USD", "availability": "https://schema.org/InStock", - Network accessline 22
"priceCurrency": "USD", "availability": "https://schema.org/InStock", "itemCondition": "https://schema.org/NewCondition", - Network accessline 23
"availability": "https://schema.org/InStock", - Network accessline 24
"itemCondition": "https://schema.org/NewCondition", - Network accessline 53
"@type": "MerchantReturnPolicy", "applicableCountry": "US", "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", - Network accessline 54
"applicableCountry": "US", "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", "merchantReturnDays": 30, - Network accessline 55
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", - Network accessline 56
"merchantReturnDays": 30, "returnMethod": "https://schema.org/ReturnByMail", "returnFees": "https://schema.org/FreeReturn" - Network accessline 57
"returnMethod": "https://schema.org/ReturnByMail", - Network accessline 58
"returnFees": "https://schema.org/FreeReturn"
skills/ultimate-seo/assets/jsonld/software-application.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 3
"@type": "SoftwareApplication", "name": "App name", "url": "https://www.example.com/", - Network accessline 4
"name": "App name", "url": "https://www.example.com/", "applicationCategory": "BusinessApplication", - Network accessline 5
"url": "https://www.example.com/", - Network accessline 13
}, "publisher": { "@id": "https://www.example.com/#organization" - Network accessline 14
"publisher": { "@id": "https://www.example.com/#organization" }, - Network accessline 15
"@id": "https://www.example.com/#organization"
skills/ultimate-seo/assets/jsonld/video.json
- Network accessline 1
{ "@context": "https://schema.org", - Network accessline 2
"@context": "https://schema.org", - Network accessline 5
"description": "What the video covers.", "thumbnailUrl": [ "https://www.example.com/videos/thumb-1280x720.jpg" - Network accessline 6
"thumbnailUrl": [ "https://www.example.com/videos/thumb-1280x720.jpg" ], - Network accessline 7
"https://www.example.com/videos/thumb-1280x720.jpg" - Network accessline 9
"uploadDate": "2026-04-01T08:00:00+00:00", "duration": "PT4M30S", "contentUrl": "https://www.example.com/videos/video.mp4", - Network accessline 10
"duration": "PT4M30S", "contentUrl": "https://www.example.com/videos/video.mp4", "embedUrl": "https://www.youtube.com/embed/VIDEO_ID" - Network accessline 11
"contentUrl": "https://www.example.com/videos/video.mp4", - Network accessline 12
"embedUrl": "https://www.youtube.com/embed/VIDEO_ID"
skills/ultimate-seo/assets/llms.txt
- Network accessline 9
- [Home](https://www.example.com/): what the product does, in one line - Network accessline 10
- [Pricing](https://www.example.com/pricing): plans and what's included - Network accessline 11
- [Features](https://www.example.com/features): the main capabilities - Network accessline 15
- [Getting started](https://www.example.com/docs/getting-started): set up in five minutes - Network accessline 16
- [API reference](https://www.example.com/docs/api): endpoints and authentication - Network accessline 20
- [About](https://www.example.com/about): team, mission and history - Network accessline 21
- [Contact](https://www.example.com/contact): support and sales channels - Network accessline 25
- [Blog](https://www.example.com/blog): announcements and guides - Network accessline 26
- [Changelog](https://www.example.com/changelog): release history
skills/ultimate-seo/assets/robots.txt
- Network accessline 1
# robots.txt — template from the ultimate-seo skill. # Replace https://www.example.com with the production origin, and adjust the - Network accessline 2
# Replace https://www.example.com with the production origin, and adjust the - Network accessline 32
Sitemap: https://www.example.com/sitemap.xml
skills/ultimate-seo/evals/audit-only-no-code-changes/files/astro.config.mjs
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/audit-only-no-code-changes/files/package.json
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/audit-only-no-code-changes/place-files.sh
- Executable scriptline 1
#!/usr/bin/env bash
skills/ultimate-seo/evals/nextjs-blog-full-setup/files/app/about/page.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/nextjs-blog-full-setup/files/app/blog/[slug]/page.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/nextjs-blog-full-setup/files/app/blog/page.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/nextjs-blog-full-setup/files/app/layout.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/nextjs-blog-full-setup/files/app/page.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/nextjs-blog-full-setup/files/lib/posts.ts
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/nextjs-blog-full-setup/files/package.json
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/nextjs-blog-full-setup/graders/01-metadata-base-and-template.md
- Network accessline 7
app/layout.tsx exports metadata with metadataBase built from https://www.jamiecodes.dev (directly or via an env var/config with that fallback) and a title template.
skills/ultimate-seo/evals/nextjs-blog-full-setup/place-files.sh
- Executable scriptline 1
#!/usr/bin/env bash
skills/ultimate-seo/evals/nextjs-blog-full-setup/prompt.md
- Network accessline 8
hey, i've got a little nextjs blog (app router) that i'm about to launch at https://www.jamiecodes.dev. can you sort out all the SEO stuff properly? i want it to actually show up on google
skills/ultimate-seo/evals/static-html-local-bakery/graders/01-unique-heads.md
- Network accessline 7
index.html, menu.html and contact.html each have a unique title and meta description, an absolute canonical on https://rosasbakerypdx.com (with or without www, consistently), html lang, viewport and Open Graph tags.
skills/ultimate-seo/evals/static-html-local-bakery/place-files.sh
- Executable scriptline 1
#!/usr/bin/env bash
skills/ultimate-seo/evals/vite-react-spa-landing/files/package.json
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/vite-react-spa-landing/files/public/favicon.svg
- Network accessline 1
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="6" fill="#0e7c66"/></svg>
skills/ultimate-seo/evals/vite-react-spa-landing/files/src/App.tsx
- Executable scriptline 1
Executable file - Network accessline 10
<nav> <Link to="/">Tidyhive</Link> <Link to="/features">Features</Link> <Link to="/pricing">Pricing</Link> <Link to="/about">About</Link> <span onClick={() => (window.location.href = "https://app.tidyhive.com/signup")}>Start - Network accessline 11
<Link to="/">Tidyhive</Link> <Link to="/features">Features</Link> <Link to="/pricing">Pricing</Link> <Link to="/about">About</Link> <span onClick={() => (window.location.href = "https://app.tidyhive.com/signup")}>Start free trial</s - Network accessline 12
<span onClick={() => (window.location.href = "https://app.tidyhive.com/signup")}>Start free trial</span>
skills/ultimate-seo/evals/vite-react-spa-landing/files/src/main.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/vite-react-spa-landing/files/src/pages/About.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/vite-react-spa-landing/files/src/pages/Features.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/vite-react-spa-landing/files/src/pages/Home.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/vite-react-spa-landing/files/src/pages/Pricing.tsx
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/vite-react-spa-landing/files/vite.config.ts
- Executable scriptline 1
Executable file
skills/ultimate-seo/evals/vite-react-spa-landing/graders/04-robots-sitemap-public.md
- Network accessline 7
public/robots.txt (or a generated equivalent) and a sitemap listing https://tidyhive.com routes exist, with robots.txt referencing the absolute sitemap URL.
skills/ultimate-seo/evals/vite-react-spa-landing/place-files.sh
- Executable scriptline 1
#!/usr/bin/env bash
skills/ultimate-seo/evals/vite-react-spa-landing/prompt.md
- Network accessline 8
We're launching Tidyhive (scheduling software for cleaning companies) next week. The marketing site is this Vite + React app with react-router. Our SEO person says Google "can't see" our pages and link previews on LinkedIn and Slack are bla
skills/ultimate-seo/references/ai-search.md
- Network accessline 82
Sitemap: https://www.example.com/sitemap.xml - Network accessline 113
Sitemap: https://www.example.com/sitemap.xml - Network accessline 125
- **Google**: `nosnippet`, `max-snippet:N`, and `data-nosnippet` apply to AI Overviews/AI Mode as well as classic snippets. `noindex` removes the page entirely. - **Bing/Copilot**: `<meta name="robots" content="nocache">` limits Copilot to - Network accessline 126
- **Bing/Copilot**: `<meta name="robots" content="nocache">` limits Copilot to titles/URLs/snippets; `noarchive` excludes content from Copilot answers. Verify against current docs: https://blogs.bing.com/webmaster - Network accessline 147
## Product - [Features](https://www.example.com/features): Invoicing, recurring billing, reminders, multi-currency - Network accessline 148
- [Features](https://www.example.com/features): Invoicing, recurring billing, reminders, multi-currency - Network accessline 149
- [Pricing](https://www.example.com/pricing): Plans and limits - Network accessline 151
## Docs - [Getting started](https://www.example.com/docs/getting-started.md): Create your first invoice in 5 minutes - Network accessline 152
- [Getting started](https://www.example.com/docs/getting-started.md): Create your first invoice in 5 minutes - Network accessline 153
- [API reference](https://www.example.com/docs/api.md): REST API for invoices and clients - Network accessline 155
## Optional - [Blog](https://www.example.com/blog): Guides on freelancing finances - Network accessline 156
- [Blog](https://www.example.com/blog): Guides on freelancing finances - Network accessline 169
- SSR/SSG/prerender all public content. - Main content, headings, and key facts in HTML — not in images, canvases, or tabs loaded on click. - Test: `curl -A "GPTBot" -s https://site/page | sed 's/<[^>]*>//g' | grep -c "your key phrase"`. - Network accessline 170
- Main content, headings, and key facts in HTML — not in images, canvases, or tabs loaded on click. - Test: `curl -A "GPTBot" -s https://site/page | sed 's/<[^>]*>//g' | grep -c "your key phrase"`. - Don't block AI crawlers by accident with - Network accessline 171
- Test: `curl -A "GPTBot" -s https://site/page | sed 's/<[^>]*>//g' | grep -c "your key phrase"`.
skills/ultimate-seo/references/content-strategy.md
- Network accessline 144
Verify against current docs: https://developers.google.com/search/docs/essentials/spam-policies and https://developers.google.com/search/docs/fundamentals/creating-helpful-content - Network accessline 209
For blogs, news, changelogs, podcasts: - Provide an RSS 2.0 or Atom feed with full or summary content, absolute URLs, `pubDate`/`updated`. - Advertise it: `<link rel="alternate" type="application/rss+xml" title="Site Blog" href="https://exa - Network accessline 210
- Provide an RSS 2.0 or Atom feed with full or summary content, absolute URLs, `pubDate`/`updated`. - Advertise it: `<link rel="alternate" type="application/rss+xml" title="Site Blog" href="https://example.com/rss.xml">`. - Feeds help disco - Network accessline 211
- Advertise it: `<link rel="alternate" type="application/rss+xml" title="Site Blog" href="https://example.com/rss.xml">`.
skills/ultimate-seo/references/ecommerce.md
- Network accessline 57
Google has two product experiences: **product snippets** (review stars/price in organic results) and **merchant listings** (Shopping tab, product knowledge panels, free listings) — merchant listings require offer details. Reference: https:/ - Network accessline 60
{ "@context": "https://schema.org", - Network accessline 61
"@context": "https://schema.org", - Network accessline 62
"@type": "Product", "@id": "https://example.com/products/nimbus-26#product", "name": "Nimbus 26 Women's Running Shoe", - Network accessline 63
"@id": "https://example.com/products/nimbus-26#product", - Network accessline 69
"brand": { "@type": "Brand", "name": "Example Brand" }, "image": [ "https://example.com/img/nimbus-26-1x1.jpg", - Network accessline 70
"image": [ "https://example.com/img/nimbus-26-1x1.jpg", "https://example.com/img/nimbus-26-4x3.jpg", - Network accessline 71
"https://example.com/img/nimbus-26-1x1.jpg", - Network accessline 72
"https://example.com/img/nimbus-26-4x3.jpg", - Network accessline 73
"https://example.com/img/nimbus-26-16x9.jpg" - Network accessline 75
"offers": { "@type": "Offer", "url": "https://example.com/products/nimbus-26", - Network accessline 76
"@type": "Offer", "url": "https://example.com/products/nimbus-26", "priceCurrency": "USD", - Network accessline 77
"url": "https://example.com/products/nimbus-26", - Network accessline 79
"price": "159.99", "priceValidUntil": "2026-12-31", "availability": "https://schema.org/InStock", - Network accessline 80
"priceValidUntil": "2026-12-31", "availability": "https://schema.org/InStock", "itemCondition": "https://schema.org/NewCondition", - Network accessline 81
"availability": "https://schema.org/InStock", - Network accessline 82
"itemCondition": "https://schema.org/NewCondition", - Network accessline 94
"@type": "MerchantReturnPolicy", "applicableCountry": "US", "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", - Network accessline 95
"applicableCountry": "US", "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", "merchantReturnDays": 30, - Network accessline 96
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", - Network accessline 97
"merchantReturnDays": 30, "returnMethod": "https://schema.org/ReturnByMail", "returnFees": "https://schema.org/FreeReturn" - Network accessline 98
"returnMethod": "https://schema.org/ReturnByMail", - Network accessline 99
"returnFees": "https://schema.org/FreeReturn" - Network accessline 114
- `availability` must match what the page shows and what Merchant Center feeds say. - Use GTIN/MPN/brand when they exist — they strengthen product matching. - Store-wide shipping and return policies can also be declared once at the organiza - Network accessline 115
- Use GTIN/MPN/brand when they exist — they strengthen product matching. - Store-wide shipping and return policies can also be declared once at the organization level (`Organization` → `hasMerchantReturnPolicy`, and shipping policy support - Network accessline 116
- Store-wide shipping and return policies can also be declared once at the organization level (`Organization` → `hasMerchantReturnPolicy`, and shipping policy support in Organization markup) and/or in Merchant Center; page-level markup over - Network accessline 117
- Variants: Google supports `ProductGroup` with `hasVariant` and `variesBy` (size, color...) — use it when variants share a page. Reference: https://developers.google.com/search/docs/appearance/structured-data/product-variants - Network accessline 118
- Sale prices: use `priceSpecification` with `UnitPriceSpecification` and `priceType` `https://schema.org/StrikethroughPrice` for the original price (verify current docs). - Network accessline 123
Human tasks for the playbook: 1. Create a Merchant Center account (https://merchants.google.com), verify and claim the website. - Network accessline 124
1. Create a Merchant Center account (https://merchants.google.com), verify and claim the website. - Network accessline 151
- Block crawling of parameter patterns in `robots.txt` when crawl volume is a problem (e.g. `Disallow: /*?*sort=`, `Disallow: /*?*price=`). Don't combine robots.txt blocking with expecting `noindex` to be seen. 3. Keep consistent parameter - Network accessline 153
4. Google's guidance (verify against current docs): https://developers.google.com/search/docs/crawling-indexing/crawling-managing-faceted-navigation
skills/ultimate-seo/references/frameworks/angular.md
- Network accessline 42
export const SITE = { name: "Acme", url: "https://www.example.com", // replaced per environment via fileReplacements, or read from environment.ts - Network accessline 43
name: "Acme", url: "https://www.example.com", // replaced per environment via fileReplacements, or read from environment.ts description: "Acme helps small teams ship invoices in minutes.", - Network accessline 44
url: "https://www.example.com", // replaced per environment via fileReplacements, or read from environment.ts - Network accessline 152
const p = this.post(); this.seo.set({ title: p.title, description: p.excerpt, path: `/blog/${p.slug}`, type: "article", jsonLd: { "@context": "https://schema.org", "@type": "BlogPosting", headline: p.title, datePublished: p.pu - Network accessline 153
this.seo.set({ title: p.title, description: p.excerpt, path: `/blog/${p.slug}`, type: "article", jsonLd: { "@context": "https://schema.org", "@type": "BlogPosting", headline: p.title, datePublished: p.publishedAt } }); }); - Network accessline 154
jsonLd: { "@context": "https://schema.org", "@type": "BlogPosting", headline: p.title, datePublished: p.publishedAt } }); - Network accessline 182
- `public/robots.txt`, `public/llms.txt`, icons and `manifest.webmanifest` (templates in `assets/`). Ensure `angular.json` `assets` includes them (default `public/**` in 17+). - Sitemap: after `ng build`, run `python3 <skill-dir>/scripts/ge - Network accessline 183
- Sitemap: after `ng build`, run `python3 <skill-dir>/scripts/generate_sitemap.py dist/<app>/browser --base-url https://www.example.com` for prerendered output, or add a postbuild Node script that reads the same slug source used by `getPrer - Network accessline 201
python3 <skill-dir>/scripts/seo_audit.py dist/<app>/browser npm run serve:ssr:<app> & # SSR server, usually :4000 python3 <skill-dir>/scripts/seo_audit.py http://localhost:4000 --crawl 50 - Network accessline 202
npm run serve:ssr:<app> & # SSR server, usually :4000 python3 <skill-dir>/scripts/seo_audit.py http://localhost:4000 --crawl 50 curl -s http://localhost:4000/pricing | grep -iE "<title>|canonical|og:title" - Network accessline 203
python3 <skill-dir>/scripts/seo_audit.py http://localhost:4000 --crawl 50 curl -s http://localhost:4000/pricing | grep -iE "<title>|canonical|og:title" curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4000/nope # 404 - Network accessline 204
curl -s http://localhost:4000/pricing | grep -iE "<title>|canonical|og:title" - Network accessline 205
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4000/nope # 404
skills/ultimate-seo/references/frameworks/astro.md
- Network accessline 49
export default defineConfig({ site: process.env.SITE_URL ?? "https://www.example.com", - Network accessline 50
site: process.env.SITE_URL ?? "https://www.example.com", - Network accessline 192
const url = new URL(Astro.url.pathname, Astro.site); const jsonLd = { "@context": "https://schema.org", - Network accessline 193
const jsonLd = { "@context": "https://schema.org", "@type": "BlogPosting", - Network accessline 194
"@context": "https://schema.org", - Network accessline 285
SITE_URL=https://www.example.com npx astro build - Network accessline 288
ls dist/sitemap-index.xml dist/robots.txt dist/og/ npx astro preview & # :4321 curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4321/nope # 404 - Network accessline 290
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4321/nope # 404
skills/ultimate-seo/references/frameworks/cms-platforms.md
- Network accessline 135
Mostly UI configuration — put click-paths in the playbook: - Site settings → SEO: auto-generate sitemap on, robots.txt content, canonical tag URL (set to `https://www.example.com`), redirects (301 table). - Network accessline 136
- Site settings → SEO: auto-generate sitemap on, robots.txt content, canonical tag URL (set to `https://www.example.com`), redirects (301 table). - Network accessline 189
python3 <skill-dir>/scripts/seo_audit.py https://www.example.com --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py https://www.example.com/ curl -s https://www.example.com/robots.txt - Network accessline 190
python3 <skill-dir>/scripts/validate_jsonld.py https://www.example.com/ curl -s https://www.example.com/robots.txt curl -s https://www.example.com/sitemap.xml | head # WP core: /wp-sitemap.xml ; Yoast/Rank Math: /sitemap_index.xml - Network accessline 191
curl -s https://www.example.com/robots.txt - Network accessline 192
curl -s https://www.example.com/sitemap.xml | head # WP core: /wp-sitemap.xml ; Yoast/Rank Math: /sitemap_index.xml - Network accessline 193
curl -s https://www.example.com/ | grep -c 'og:title' # expect 1 - Network accessline 196
Shopify theme dev: `shopify theme dev` then audit `http://127.0.0.1:9292`. WordPress local (wp-env/LocalWP): audit the local URL.
skills/ultimate-seo/references/frameworks/gatsby.md
- Network accessline 47
titleTemplate: "%s | Acme", description: "Acme helps small teams ship invoices in minutes.", siteUrl: (process.env.SITE_URL || "https://www.example.com").replace(/\/$/, ""), - Network accessline 48
description: "Acme helps small teams ship invoices in minutes.", siteUrl: (process.env.SITE_URL || "https://www.example.com").replace(/\/$/, ""), image: "/og.png", - Network accessline 49
siteUrl: (process.env.SITE_URL || "https://www.example.com").replace(/\/$/, ""), - Network accessline 140
<Seo title={post.frontmatter!.title!} description={post.excerpt!} pathname={location.pathname} article> <script type="application/ld+json">{JSON.stringify({ "@context": "https://schema.org", - Network accessline 141
<script type="application/ld+json">{JSON.stringify({ "@context": "https://schema.org", "@type": "BlogPosting", - Network accessline 142
"@context": "https://schema.org", - Network accessline 197
SITE_URL=https://www.example.com npx gatsby build - Network accessline 200
ls public/sitemap-index.xml public/robots.txt public/manifest.webmanifest npx gatsby serve & # :9000 curl -s -o /dev/null -w "%{http_code}\n" http://localhost:9000/nope # 404 - Network accessline 202
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:9000/nope # 404
skills/ultimate-seo/references/frameworks/nextjs-app-router.md
- Network accessline 50
export const siteConfig = { name: "Acme", url: (process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000").replace(/\/$/, ""), - Network accessline 51
name: "Acme", url: (process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000").replace(/\/$/, ""), description: "Acme helps small teams ship invoices in minutes.", - Network accessline 52
url: (process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000").replace(/\/$/, ""), - Network accessline 63
On Vercel, `VERCEL_PROJECT_PRODUCTION_URL` (no protocol) is available at build time; a common fallback is `process.env.NEXT_PUBLIC_SITE_URL ?? (process.env.VERCEL_PROJECT_PRODUCTION_URL ? \`https://${process.env.VERCEL_PROJECT_PRODUCTION_UR - Network accessline 254
- File-based images automatically emit `og:image`, `og:image:width/height/type/alt`, with absolute URLs via `metadataBase`. Add `twitter-image.tsx` or re-export: `export { default, alt, size, contentType } from "./opengraph-image";`. - Sato - Network accessline 255
- Satori supports flexbox and a CSS subset only; every multi-child `div` needs `display: "flex"`. Load custom fonts with `fetch(new URL("./Inter-Bold.ttf", import.meta.url)).then(r => r.arrayBuffer())` (edge) or `readFile` (node) and pass ` - Network accessline 320
npm run build # metadata errors and missing metadataBase warnings appear here npm run start & # or: npx next start -p 3000 python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 - Network accessline 321
npm run start & # or: npx next start -p 3000 python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ - Network accessline 322
python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/robots.txt; curl -s http://localhost:3000/sitemap.xml | head -40 - Network accessline 323
python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/robots.txt; curl -s http://localhost:3000/sitemap.xml | head -40 curl -sI http://localhost:3000/opengraph-image | head -5 - Network accessline 324
curl -s http://localhost:3000/robots.txt; curl -s http://localhost:3000/sitemap.xml | head -40 - Network accessline 325
curl -sI http://localhost:3000/opengraph-image | head -5 - Network accessline 326
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/definitely-missing # expect 404
skills/ultimate-seo/references/frameworks/nextjs-pages-router.md
- Network accessline 46
export const siteConfig = { name: "Acme", url: (process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000").replace(/\/$/, ""), - Network accessline 47
name: "Acme", url: (process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000").replace(/\/$/, ""), description: "Acme helps small teams ship invoices in minutes.", - Network accessline 48
url: (process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000").replace(/\/$/, ""), - Network accessline 136
<Seo title={post.title} description={post.excerpt} path={path} type="article" image={`/api/og?title=${encodeURIComponent(post.title)}`} publishedTime={post.publishedAt} modifiedTime={post.updatedAt} /> <JsonLd data={{ "@contex - Network accessline 137
<JsonLd data={{ "@context": "https://schema.org", "@type": "BlogPosting", headline: post.title, description: post.excerpt, url: absoluteUrl(path), - Network accessline 138
"@context": "https://schema.org", "@type": "BlogPosting", - Network accessline 171
/** @type {import('next-sitemap').IConfig} */ module.exports = { siteUrl: process.env.NEXT_PUBLIC_SITE_URL || "https://www.example.com", - Network accessline 172
module.exports = { siteUrl: process.env.NEXT_PUBLIC_SITE_URL || "https://www.example.com", generateRobotsTxt: true, - Network accessline 173
siteUrl: process.env.NEXT_PUBLIC_SITE_URL || "https://www.example.com", - Network accessline 198
]; const xml = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 199
const xml = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${urls.map((u) => ` <url><loc>${esc(siteConfig.url + u.loc)}</loc>${u.lastmod ? `<lastmod>${u.lastmod}</lastmod>` : ""}</url>` - Network accessline 200
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 277
npm run build && npm run start & python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 - Network accessline 278
python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/sitemap.xml | head -30; curl -s http://localhost:3000/robots.txt - Network accessline 279
python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/sitemap.xml | head -30; curl -s http://localhost:3000/robots.txt curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/blog/does-no - Network accessline 280
curl -s http://localhost:3000/sitemap.xml | head -30; curl -s http://localhost:3000/robots.txt - Network accessline 281
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/blog/does-not-exist # 404
skills/ultimate-seo/references/frameworks/nuxt-vue.md
- Network accessline 47
modules: ['@nuxtjs/seo'], site: { url: 'https://www.example.com', // overridden by NUXT_PUBLIC_SITE_URL / NUXT_SITE_URL - Network accessline 48
site: { url: 'https://www.example.com', // overridden by NUXT_PUBLIC_SITE_URL / NUXT_SITE_URL name: 'Example', - Network accessline 49
url: 'https://www.example.com', // overridden by NUXT_PUBLIC_SITE_URL / NUXT_SITE_URL - Network accessline 183
setHeader(event, 'content-type', 'application/xml; charset=utf-8') return `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 184
return `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${urls.map((u) => ` <url><loc>${new URL(u.loc, site).href}</loc>${u.lastmod ? `<lastmod>${u.lastmod}</lastmod>` : ''}</url>`).join( - Network accessline 185
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 216
name: 'Example', logo: '/logo.png', sameAs: ['https://github.com/example'], // only real profiles - Network accessline 217
logo: '/logo.png', sameAs: ['https://github.com/example'], // only real profiles }, - Network accessline 218
sameAs: ['https://github.com/example'], // only real profiles - Network accessline 256
npx nuxi build && node .output/server/index.mjs & # or: npx nuxi generate && npx serve .output/public python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 - Network accessline 257
python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/robots.txt; curl -s http://localhost:3000/sitemap.xml | head -20 - Network accessline 258
python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/robots.txt; curl -s http://localhost:3000/sitemap.xml | head -20 curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/definitely-n - Network accessline 259
curl -s http://localhost:3000/robots.txt; curl -s http://localhost:3000/sitemap.xml | head -20 - Network accessline 260
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/definitely-not-a-page # expect 404
skills/ultimate-seo/references/frameworks/react-router-remix.md
- Network accessline 45
export const siteConfig = { name: "Acme", url: (process.env.SITE_URL ?? "http://localhost:5173").replace(/\/$/, ""), - Network accessline 46
name: "Acme", url: (process.env.SITE_URL ?? "http://localhost:5173").replace(/\/$/, ""), description: "Acme helps small teams ship invoices in minutes.", - Network accessline 47
url: (process.env.SITE_URL ?? "http://localhost:5173").replace(/\/$/, ""), - Network accessline 159
{ "script:ld+json": { "@context": "https://schema.org", - Network accessline 160
"script:ld+json": { "@context": "https://schema.org", "@type": "BlogPosting", - Network accessline 161
"@context": "https://schema.org", - Network accessline 198
]; const body = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 199
const body = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${urls.map((u) => ` <url><loc>${esc(siteConfig.url + u.loc)}</loc>${u.lastmod ? `<lastmod>${u.lastmod}</lastmod>` : ""}</url> - Network accessline 200
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 247
npm run build && npm run start & # react-router-serve ./build/server/index.js (port 3000) python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 - Network accessline 248
python3 <skill-dir>/scripts/seo_audit.py http://localhost:3000 --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/sitemap.xml | head -20 - Network accessline 249
python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:3000/ curl -s http://localhost:3000/sitemap.xml | head -20 curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/does-not-exist # 404 - Network accessline 250
curl -s http://localhost:3000/sitemap.xml | head -20 - Network accessline 251
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/does-not-exist # 404
skills/ultimate-seo/references/frameworks/react-spa.md
- Network accessline 57
export const siteConfig = { name: "Acme", url: (import.meta.env.VITE_SITE_URL ?? "https://www.example.com").replace(/\/$/, ""), - Network accessline 58
name: "Acme", url: (import.meta.env.VITE_SITE_URL ?? "https://www.example.com").replace(/\/$/, ""), description: "Acme helps small teams ship invoices in minutes.", - Network accessline 59
url: (import.meta.env.VITE_SITE_URL ?? "https://www.example.com").replace(/\/$/, ""), - Network accessline 169
// scripts/generate-sitemap.mjs — run after vite build: "build": "vite build && node scripts/generate-sitemap.mjs" import { writeFileSync } from "node:fs"; const SITE = (process.env.VITE_SITE_URL || "https://www.example.com").replace(/\/$/ - Network accessline 170
import { writeFileSync } from "node:fs"; const SITE = (process.env.VITE_SITE_URL || "https://www.example.com").replace(/\/$/, ""); const routes = ["/", "/pricing", "/about", "/blog"]; // import from your routes/data if possible - Network accessline 171
const SITE = (process.env.VITE_SITE_URL || "https://www.example.com").replace(/\/$/, ""); - Network accessline 173
// const posts = JSON.parse(readFileSync("src/content/posts.json", "utf8")); routes.push(...posts.map(p => `/blog/${p.slug}`)); const xml = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 174
const xml = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${routes.map((r) => ` <url><loc>${SITE}${r}</loc></url>`).join("\n")} - Network accessline 175
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 224
npm run build && npx vite preview --port 4173 & # Raw HTML is what scrapers see — this is the important check for SPAs: curl -s http://localhost:4173/pricing | grep -iE "<title>|og:title|canonical|<h1" - Network accessline 225
# Raw HTML is what scrapers see — this is the important check for SPAs: curl -s http://localhost:4173/pricing | grep -iE "<title>|og:title|canonical|<h1" python3 <skill-dir>/scripts/seo_audit.py dist # prerendered files - Network accessline 226
curl -s http://localhost:4173/pricing | grep -iE "<title>|og:title|canonical|<h1" - Network accessline 227
python3 <skill-dir>/scripts/seo_audit.py dist # prerendered files python3 <skill-dir>/scripts/seo_audit.py http://localhost:4173 --crawl 30 python3 <skill-dir>/scripts/validate_jsonld.py dist - Network accessline 228
python3 <skill-dir>/scripts/seo_audit.py http://localhost:4173 --crawl 30 python3 <skill-dir>/scripts/validate_jsonld.py dist curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4173/nope # vite preview returns 200 (SPA fallback) — - Network accessline 230
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4173/nope # vite preview returns 200 (SPA fallback) — check host config separately
skills/ultimate-seo/references/frameworks/server-rendered.md
- Network accessline 48
[Credential-related source omitted] - Access to secretsline 48
[Credential-related source omitted] - Network accessline 191
`config/application.rb`: `config.x.site_url = ENV.fetch("SITE_URL", "https://www.example.com")`, `config.x.site_name = "Example"`. Set `config.action_controller.asset_host`/`default_url_options[:host]` so `image_url` is absolute and correct - Network accessline 210
SitemapGenerator::Sitemap.default_host = ENV.fetch("SITE_URL") - Network accessline 325
# start the app locally (examples) python manage.py runserver 8000 | bin/rails s -p 3000 | php artisan serve | node server.js | go run . | dotnet run python3 <skill-dir>/scripts/seo_audit.py http://localhost:8000 --crawl 50 - Network accessline 326
python manage.py runserver 8000 | bin/rails s -p 3000 | php artisan serve | node server.js | go run . | dotnet run python3 <skill-dir>/scripts/seo_audit.py http://localhost:8000 --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py http - Network accessline 327
python3 <skill-dir>/scripts/seo_audit.py http://localhost:8000 --crawl 50 python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:8000/ curl -s http://localhost:8000/robots.txt; curl -s http://localhost:8000/sitemap.xml | head - Network accessline 328
python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:8000/ curl -s http://localhost:8000/robots.txt; curl -s http://localhost:8000/sitemap.xml | head curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8000/blog/does-not-ex - Network accessline 329
curl -s http://localhost:8000/robots.txt; curl -s http://localhost:8000/sitemap.xml | head - Network accessline 330
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8000/blog/does-not-exist # 404 - Network accessline 337
- Canonicals built from `request.host` / `request.build_absolute_uri()` behind a proxy → `http://` or internal hostnames. Use the configured `SITE_URL`. - Debug/staging environments indexable: add `X-Robots-Tag: noindex` header (middleware)
skills/ultimate-seo/references/frameworks/static-html.md
- Network accessline 49
<title>Handmade Oak Desks, Built to Order · Example Studio</title> <meta name="description" content="Solid oak desks made to your measurements in Portland. Free design consult, 8-week build, lifetime joinery warranty."> <link rel="canon - Network accessline 51
<link rel="canonical" href="https://www.example.com/desks/"> - Network accessline 57
<meta property="og:title" content="Handmade Oak Desks, Built to Order"> <meta property="og:description" content="Solid oak desks made to your measurements in Portland."> <meta property="og:url" content="https://www.example.com/desks/"> - Network accessline 58
<meta property="og:description" content="Solid oak desks made to your measurements in Portland."> <meta property="og:url" content="https://www.example.com/desks/"> <meta property="og:image" content="https://www.example.com/og/desks.png" - Network accessline 59
<meta property="og:url" content="https://www.example.com/desks/"> - Network accessline 60
<meta property="og:image" content="https://www.example.com/og/desks.png"> - Network accessline 79
<script type="application/ld+json"> { "@context": "https://schema.org", - Network accessline 80
{ "@context": "https://schema.org", "@type": "BreadcrumbList", - Network accessline 81
"@context": "https://schema.org", - Network accessline 82
"@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://www.example.com/" }, - Network accessline 83
"itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://www.example.com/" }, { "@type": "ListItem", "position": 2, "name": "Desks", "item": "https://www.example.com/desks/" } - Network accessline 84
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://www.example.com/" }, - Network accessline 85
{ "@type": "ListItem", "position": 2, "name": "Desks", "item": "https://www.example.com/desks/" } - Network accessline 124
Sitemap: https://www.example.com/sitemap.xml - Network accessline 132
python3 <skill-dir>/scripts/generate_sitemap.py . --base-url https://www.example.com --lastmod git - Network accessline 140
<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 141
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 142
<url><loc>https://www.example.com/</loc><lastmod>2026-10-01</lastmod></url> - Network accessline 143
<url><loc>https://www.example.com/desks/</loc><lastmod>2026-09-14</lastmod></url> - Network accessline 175
| Cloudflare Pages | `404.html` | `_redirects` file | | Apache | `ErrorDocument 404 /404.html` | `.htaccess` `Redirect 301 /old /new` or `RewriteRule` for host canonicalization | | Nginx | `error_page 404 /404.html;` | `return 301 https://w - Network accessline 177
| Nginx | `error_page 404 /404.html;` | `return 301 https://www.example.com$request_uri;` server block | - Network accessline 190
Home page: `Organization` (or `LocalBusiness`/`Person`) + `WebSite` from `assets/jsonld/`. Inner pages: `BreadcrumbList` + the page's type. Keep the `@id` of the organization stable (`https://www.example.com/#organization`) and reference it - Network accessline 196
python3 <skill-dir>/scripts/validate_jsonld.py . python3 -m http.server 8080 & # then: curl -sI http://localhost:8080/robots.txt - Network accessline 198
curl -sI http://localhost:8080/robots.txt - Network accessline 201
After deploy: `curl -sI https://example.com/` should 301 to the canonical host; `curl -s -o /dev/null -w '%{http_code}' https://www.example.com/nope` → `404`.
skills/ultimate-seo/references/frameworks/static-site-generators.md
- Network accessline 38
baseURL = "https://www.example.com/" - Network accessline 93
# _config.yml url: "https://www.example.com" # no trailing slash - Network accessline 94
url: "https://www.example.com" # no trailing slash - Network accessline 105
name: Example links: - https://github.com/example - Network accessline 106
links: - https://github.com/example plugins: - Network accessline 107
- https://github.com/example - Network accessline 137
// _data/site.js export default { url: process.env.SITE_URL || 'https://www.example.com', - Network accessline 138
export default { url: process.env.SITE_URL || 'https://www.example.com', name: 'Example', - Network accessline 139
url: process.env.SITE_URL || 'https://www.example.com', - Network accessline 177
--- <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 178
<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> {%- for p in collections.all %}{% if not p.data.noindex and not p.data.eleventyExcludeFromCollections %} - Network accessline 179
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 191
// docusaurus.config.ts const config = { url: 'https://docs.example.com', - Network accessline 192
const config = { url: 'https://docs.example.com', baseUrl: '/', - Network accessline 193
url: 'https://docs.example.com', - Network accessline 208
headTags: [ { tagName: 'script', attributes: { type: 'application/ld+json' }, innerHTML: JSON.stringify({ '@context': 'https://schema.org', '@type': 'Organization', name: 'Example', url: 'https://example.com', logo: 'https://docs. - Network accessline 209
{ tagName: 'script', attributes: { type: 'application/ld+json' }, innerHTML: JSON.stringify({ '@context': 'https://schema.org', '@type': 'Organization', name: 'Example', url: 'https://example.com', logo: 'https://docs.example.com/img/ - Network accessline 210
innerHTML: JSON.stringify({ '@context': 'https://schema.org', '@type': 'Organization', name: 'Example', url: 'https://example.com', logo: 'https://docs.example.com/img/logo.png' }) }, - Network accessline 221
// .vitepress/config.mts import { defineConfig } from 'vitepress' const SITE = 'https://docs.example.com' - Network accessline 223
const SITE = 'https://docs.example.com' - Network accessline 258
# mkdocs.yml site_name: Example Docs site_url: https://docs.example.com/ # required for sitemap + canonical - Network accessline 259
site_name: Example Docs site_url: https://docs.example.com/ # required for sitemap + canonical site_description: Default description, ~150 chars. - Network accessline 260
site_url: https://docs.example.com/ # required for sitemap + canonical - Network accessline 271
social: - icon: fontawesome/brands/github link: https://github.com/example - Network accessline 273
link: https://github.com/example
skills/ultimate-seo/references/frameworks/sveltekit.md
- Network accessline 45
export const site = { url: (PUBLIC_SITE_URL || 'https://www.example.com').replace(/\/$/, ''), - Network accessline 46
url: (PUBLIC_SITE_URL || 'https://www.example.com').replace(/\/$/, ''), - Network accessline 156
type="article" jsonLd={{ '@context': 'https://schema.org', - Network accessline 157
jsonLd={{ '@context': 'https://schema.org', '@type': 'BlogPosting', - Network accessline 158
'@context': 'https://schema.org', - Network accessline 210
]; const xml = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 211
const xml = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${urls.map((u) => ` <url><loc>${xmlEscape(u.loc)}</loc>${u.lastmod ? `<lastmod>${u.lastmod}</lastmod>` : ''}</url>`).join('\n' - Network accessline 212
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 240
npm run build && npm run preview -- --port 4173 & python3 <skill-dir>/scripts/seo_audit.py http://localhost:4173 --crawl 50 - Network accessline 241
python3 <skill-dir>/scripts/seo_audit.py http://localhost:4173 --crawl 50 - Network accessline 242
# adapter-static output: python3 <skill-dir>/scripts/seo_audit.py build python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:4173/ - Network accessline 243
python3 <skill-dir>/scripts/seo_audit.py build python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:4173/ curl -s http://localhost:4173/robots.txt; curl -s http://localhost:4173/sitemap.xml | head - Network accessline 244
python3 <skill-dir>/scripts/validate_jsonld.py http://localhost:4173/ curl -s http://localhost:4173/robots.txt; curl -s http://localhost:4173/sitemap.xml | head curl -s -o /dev/null -w '%{http_code}\n' http://localhost:4173/nope # expect - Network accessline 245
curl -s http://localhost:4173/robots.txt; curl -s http://localhost:4173/sitemap.xml | head - Network accessline 246
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:4173/nope # expect 404
skills/ultimate-seo/references/international.md
- Network accessline 44
- Pick whether the default locale gets a prefix (`/en/`) or lives at root (`/`). Either works; be consistent and make `x-default` point at the right place. - Keep the locale segment first: `/de/produkte/...`, not `/produkte/de/...`. - Googl - Network accessline 46
- Google Search Console's International Targeting report was retired; geo-targeting comes from ccTLD, hreflang, local content signals (currency, address, language), and links. Verify against current docs: https://developers.google.com/searc - Network accessline 62
<link rel="alternate" hreflang="en" href="https://example.com/en/pricing" /> - Network accessline 63
<link rel="alternate" hreflang="de" href="https://example.com/de/preise" /> - Network accessline 64
<link rel="alternate" hreflang="fr" href="https://example.com/fr/tarifs" /> - Network accessline 65
<link rel="alternate" hreflang="x-default" href="https://example.com/en/pricing" /> - Network accessline 93
Link: <https://example.com/en/guide.pdf>; rel="alternate"; hreflang="en", - Network accessline 94
<https://example.com/de/guide.pdf>; rel="alternate"; hreflang="de" - Network accessline 101
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" - Network accessline 102
xmlns:xhtml="http://www.w3.org/1999/xhtml"> - Network accessline 103
<url> <loc>https://example.com/en/pricing</loc> <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/pricing"/> - Network accessline 104
<loc>https://example.com/en/pricing</loc> - Network accessline 105
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/pricing"/> - Network accessline 106
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/preise"/> - Network accessline 107
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/pricing"/> - Network accessline 108
</url> <url> <loc>https://example.com/de/preise</loc> - Network accessline 109
<url> <loc>https://example.com/de/preise</loc> <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/pricing"/> - Network accessline 110
<loc>https://example.com/de/preise</loc> - Network accessline 111
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/pricing"/> - Network accessline 112
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/preise"/> - Network accessline 113
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/pricing"/> - Network accessline 118
Reference: https://developers.google.com/search/docs/specialty/international/localized-versions (verify against current docs).
skills/ultimate-seo/references/launch-and-monitoring.md
- Network accessline 31
- [ ] Redirects from any old URLs (see §8). - [ ] Unique titles/descriptions on key templates; OG images render (test with a social debugger). - [ ] Structured data validates (`validate_jsonld.py`, Rich Results Test https://search.google.co - Network accessline 32
- [ ] Unique titles/descriptions on key templates; OG images render (test with a social debugger). - [ ] Structured data validates (`validate_jsonld.py`, Rich Results Test https://search.google.com/test/rich-results, Schema Markup Validator - Network accessline 33
- [ ] Structured data validates (`validate_jsonld.py`, Rich Results Test https://search.google.com/test/rich-results, Schema Markup Validator https://validator.schema.org). - Network accessline 40
https://search.google.com/search-console - Network accessline 64
https://www.bing.com/webmasters - Network accessline 70
**IndexNow** (https://www.indexnow.org): a protocol to instantly notify participating search engines (Bing, Yandex, Seznam, Naver and others; Google does **not** participate as of this writing — verify against current docs) when URLs are ad - Network accessline 71
1. Generate a key; host it at `https://example.com/{key}.txt` containing the key. - Network accessline 74
curl -X POST "https://api.indexnow.org/indexnow" \ - Network accessline 76
-d '{"host":"example.com","key":"YOUR_KEY","keyLocation":"https://example.com/YOUR_KEY.txt","urlList":["https://example.com/new-page"]}' - Network accessline 108
- **Errors**: Sentry or equivalent for client/server errors (broken rendering = broken SEO). - **Real-user performance**: CrUX (via PageSpeed Insights / GSC CWV report / CrUX dashboard), `web-vitals` library sending to analytics, Vercel Spe - Network accessline 109
- **Real-user performance**: CrUX (via PageSpeed Insights / GSC CWV report / CrUX dashboard), `web-vitals` library sending to analytics, Vercel Speed Insights, Cloudflare Web Analytics, DebugBear, SpeedCurve. - **Change detection for SEO-cr - Network accessline 110
- **Change detection for SEO-critical files**: alert if `robots.txt` changes or a `noindex` appears on key pages (ContentKing/Conductor Monitoring, Little Warden, or a simple CI/cron check: `curl -s https://example.com/robots.txt | grep -q - Network accessline 134
- Revisit keyword map and roadmap; update ULTIMATE-SEO.md. - Review robots.txt AI-crawler policy against new bots/policies. - Check Google Search Central blog for core updates and policy changes: https://developers.google.com/search/blog an - Network accessline 136
- Check Google Search Central blog for core updates and policy changes: https://developers.google.com/search/blog and Google Search Status Dashboard https://status.search.google.com
skills/ultimate-seo/references/local-seo.md
- Network accessline 24
Google's stated factors (verify against current docs: https://support.google.com/business/answer/7091): - Network accessline 35
Setup: 1. Claim/create at https://business.google.com. Verify (video, phone, email, or postcard — Google chooses). - Network accessline 36
1. Claim/create at https://business.google.com. Verify (video, phone, email, or postcard — Google chooses). - Network accessline 92
Use the most specific subtype of `LocalBusiness` (`Dentist`, `Restaurant`, `Plumber`, `AutoRepair`, `LegalService`, `MedicalClinic`, `HairSalon`, `RealEstateAgent`, etc. — see https://schema.org/LocalBusiness#subtypes). Place on the home pa - Network accessline 95
{ "@context": "https://schema.org", - Network accessline 96
"@context": "https://schema.org", - Network accessline 97
"@type": "Plumber", "@id": "https://example.com/#business", "name": "Example Plumbing Co.", - Network accessline 98
"@id": "https://example.com/#business", - Network accessline 99
"name": "Example Plumbing Co.", "url": "https://example.com/", "logo": "https://example.com/logo.png", - Network accessline 100
"url": "https://example.com/", - Network accessline 101
"logo": "https://example.com/logo.png", - Network accessline 102
"image": ["https://example.com/images/storefront.jpg"], - Network accessline 132
], "sameAs": [ "https://www.facebook.com/exampleplumbing", - Network accessline 133
"sameAs": [ "https://www.facebook.com/exampleplumbing", "https://www.yelp.com/biz/example-plumbing-austin" - Network accessline 134
"https://www.facebook.com/exampleplumbing", - Network accessline 135
"https://www.yelp.com/biz/example-plumbing-austin" - Network accessline 150
Reference: https://developers.google.com/search/docs/appearance/structured-data/local-business (verify against current docs). - Network accessline 186
- **Apple Business Connect** (https://businessconnect.apple.com): controls Apple Maps, Siri, and Spotlight results — important given iPhone share. Claim, verify, add photos/hours, "Showcases" for promos. - Network accessline 187
- **Bing Places** (https://www.bingplaces.com): import from GBP in a few clicks. Bing data also powers some AI assistants and other surfaces.
skills/ultimate-seo/references/metadata.md
- Network accessline 32
<title>Invoice Software for Freelancers | Acme</title> <meta name="description" content="Send professional invoices in 60 seconds, get paid by card or bank transfer, and chase late payments automatically. Free for up to 5 clients."> <li - Network accessline 34
<link rel="canonical" href="https://www.acme.com/invoicing"> - Network accessline 38
<meta property="og:title" content="Invoice Software for Freelancers"> <meta property="og:description" content="Send professional invoices in 60 seconds and get paid faster."> <meta property="og:url" content="https://www.acme.com/invoici - Network accessline 39
<meta property="og:description" content="Send professional invoices in 60 seconds and get paid faster."> <meta property="og:url" content="https://www.acme.com/invoicing"> <meta property="og:image" content="https://www.acme.com/og/invoic - Network accessline 40
<meta property="og:url" content="https://www.acme.com/invoicing"> - Network accessline 41
<meta property="og:image" content="https://www.acme.com/og/invoicing.png"> - Network accessline 110
- One canonical per page. Frameworks plus plugins often emit two — check rendered HTML. - Cross-domain canonical is valid for syndicated content (point to the original). - HTTP header form for non-HTML (PDFs): `Link: <https://example.com/do - Network accessline 112
- HTTP header form for non-HTML (PDFs): `Link: <https://example.com/doc.pdf>; rel="canonical"`. - Network accessline 221
Google Search favicon: must be a multiple of 48×48 px (48, 96, 144…) or SVG, crawlable, stable URL, on the home page. Verify against current docs: https://developers.google.com/search/docs/appearance/favicon-in-search
skills/ultimate-seo/references/performance.md
- Network accessline 34
Verify against current docs: https://web.dev/articles/vitals - Network accessline 81
- `fetchpriority="high"` on the LCP image (framework: Next.js `priority`/`preload`, Nuxt `<NuxtImg preload>`, Astro `<Image loading="eager" fetchpriority="high">`). - If it's a CSS background or discovered late: `<link rel="preload" as="ima - Network accessline 83
- Self-host or `preconnect` the LCP image's origin: `<link rel="preconnect" href="https://cdn.example.com" crossorigin>`.
skills/ultimate-seo/references/structured-data.md
- Network accessline 51
{ "@context": "https://schema.org", - Network accessline 52
"@context": "https://schema.org", - Network accessline 54
{ "@type": "Organization", "@id": "https://www.example.com/#organization", - Network accessline 55
"@type": "Organization", "@id": "https://www.example.com/#organization", "name": "Acme", - Network accessline 56
"@id": "https://www.example.com/#organization", - Network accessline 57
"name": "Acme", "url": "https://www.example.com/", "logo": { "@type": "ImageObject", "url": "https://www.example.com/logo-512.png", "width": 512, "height": 512 } - Network accessline 58
"url": "https://www.example.com/", - Network accessline 59
"logo": { "@type": "ImageObject", "url": "https://www.example.com/logo-512.png", "width": 512, "height": 512 } - Network accessline 61
{ "@type": "WebSite", "@id": "https://www.example.com/#website", - Network accessline 62
"@type": "WebSite", "@id": "https://www.example.com/#website", "url": "https://www.example.com/", - Network accessline 63
"@id": "https://www.example.com/#website", - Network accessline 64
"url": "https://www.example.com/", - Network accessline 65
"name": "Acme", "publisher": { "@id": "https://www.example.com/#organization" } }, - Network accessline 66
"publisher": { "@id": "https://www.example.com/#organization" } - Network accessline 68
{ "@type": "WebPage", "@id": "https://www.example.com/pricing#webpage", - Network accessline 69
"@type": "WebPage", "@id": "https://www.example.com/pricing#webpage", "url": "https://www.example.com/pricing", - Network accessline 70
"@id": "https://www.example.com/pricing#webpage", - Network accessline 71
"url": "https://www.example.com/pricing", - Network accessline 72
"name": "Pricing | Acme", "isPartOf": { "@id": "https://www.example.com/#website" }, "breadcrumb": { "@id": "https://www.example.com/pricing#breadcrumb" } - Network accessline 73
"isPartOf": { "@id": "https://www.example.com/#website" }, - Network accessline 74
"breadcrumb": { "@id": "https://www.example.com/pricing#breadcrumb" } - Network accessline 89
{ "@type": "Organization", "@id": "https://www.example.com/#organization", - Network accessline 90
"@type": "Organization", "@id": "https://www.example.com/#organization", "name": "Acme", - Network accessline 91
"@id": "https://www.example.com/#organization", - Network accessline 92
"name": "Acme", "legalName": "Acme Software Ltd", "url": "https://www.example.com/", - Network accessline 93
"legalName": "Acme Software Ltd", "url": "https://www.example.com/", "logo": "https://www.example.com/logo-512.png", - Network accessline 94
"url": "https://www.example.com/", - Network accessline 95
"logo": "https://www.example.com/logo-512.png", - Network accessline 96
"description": "Invoicing software for freelancers and small agencies.", "sameAs": [ "https://www.linkedin.com/company/acme", - Network accessline 97
"sameAs": [ "https://www.linkedin.com/company/acme", "https://github.com/acme", - Network accessline 98
"https://www.linkedin.com/company/acme", - Network accessline 99
"https://github.com/acme", - Network accessline 100
"https://x.com/acme", - Network accessline 101
"https://www.wikidata.org/wiki/Q000000" - Network accessline 116
{ "@type": "WebSite", "@id": "https://www.example.com/#website", - Network accessline 117
"@type": "WebSite", "@id": "https://www.example.com/#website", "url": "https://www.example.com/", - Network accessline 118
"@id": "https://www.example.com/#website", - Network accessline 119
"url": "https://www.example.com/", - Network accessline 120
"name": "Acme", "alternateName": ["Acme Invoicing", "acme.com"], "publisher": { "@id": "https://www.example.com/#organization" }, - Network accessline 121
"alternateName": ["Acme Invoicing", "acme.com"], "publisher": { "@id": "https://www.example.com/#organization" }, "inLanguage": "en-US" - Network accessline 122
"publisher": { "@id": "https://www.example.com/#organization" }, - Network accessline 136
{ "@type": "BreadcrumbList", "@id": "https://www.example.com/blog/late-payment-email#breadcrumb", - Network accessline 137
"@type": "BreadcrumbList", "@id": "https://www.example.com/blog/late-payment-email#breadcrumb", "itemListElement": [ - Network accessline 138
"@id": "https://www.example.com/blog/late-payment-email#breadcrumb", - Network accessline 139
"itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://www.example.com/" }, { "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://www.example.com/blog" }, - Network accessline 140
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://www.example.com/" }, - Network accessline 141
{ "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://www.example.com/blog" }, - Network accessline 154
{ "@type": "BlogPosting", "@id": "https://www.example.com/blog/late-payment-email#article", - Network accessline 155
"@type": "BlogPosting", "@id": "https://www.example.com/blog/late-payment-email#article", "mainEntityOfPage": "https://www.example.com/blog/late-payment-email", - Network accessline 156
"@id": "https://www.example.com/blog/late-payment-email#article", - Network accessline 157
"mainEntityOfPage": "https://www.example.com/blog/late-payment-email", - Network accessline 159
"description": "Polite, firm and final-notice templates for chasing unpaid invoices.", "image": [ "https://www.example.com/og/late-payment-email-16x9.png", - Network accessline 160
"image": [ "https://www.example.com/og/late-payment-email-16x9.png", "https://www.example.com/og/late-payment-email-4x3.png", - Network accessline 161
"https://www.example.com/og/late-payment-email-16x9.png", - Network accessline 162
"https://www.example.com/og/late-payment-email-4x3.png", - Network accessline 163
"https://www.example.com/og/late-payment-email-1x1.png" - Network accessline 165
"datePublished": "2026-03-02T08:00:00+00:00", "dateModified": "2026-09-14T10:15:00+00:00", "author": [{ "@type": "Person", "name": "Jane Doe", "url": "https://www.example.com/authors/jane-doe" }], - Network accessline 166
"dateModified": "2026-09-14T10:15:00+00:00", "author": [{ "@type": "Person", "name": "Jane Doe", "url": "https://www.example.com/authors/jane-doe" }], "publisher": { "@id": "https://www.example.com/#organization" }, - Network accessline 167
"author": [{ "@type": "Person", "name": "Jane Doe", "url": "https://www.example.com/authors/jane-doe" }], - Network accessline 168
"publisher": { "@id": "https://www.example.com/#organization" }, - Network accessline 187
{ "@type": "Product", "@id": "https://shop.example.com/p/trail-runner-2#product", - Network accessline 188
"@type": "Product", "@id": "https://shop.example.com/p/trail-runner-2#product", "name": "Trail Runner 2 – Men's Running Shoe", - Network accessline 189
"@id": "https://shop.example.com/p/trail-runner-2#product", - Network accessline 190
"name": "Trail Runner 2 – Men's Running Shoe", "image": ["https://shop.example.com/img/trail-runner-2-1.jpg"], "description": "Lightweight trail shoe with 6mm drop and Vibram outsole.", - Network accessline 191
"image": ["https://shop.example.com/img/trail-runner-2-1.jpg"], - Network accessline 196
"offers": { "@type": "Offer", "url": "https://shop.example.com/p/trail-runner-2", - Network accessline 197
"@type": "Offer", "url": "https://shop.example.com/p/trail-runner-2", "priceCurrency": "USD", - Network accessline 198
"url": "https://shop.example.com/p/trail-runner-2", - Network accessline 200
"price": "129.00", "priceValidUntil": "2026-12-31", "availability": "https://schema.org/InStock", - Network accessline 201
"priceValidUntil": "2026-12-31", "availability": "https://schema.org/InStock", "itemCondition": "https://schema.org/NewCondition", - Network accessline 202
"availability": "https://schema.org/InStock", - Network accessline 203
"itemCondition": "https://schema.org/NewCondition", - Network accessline 215
"@type": "MerchantReturnPolicy", "applicableCountry": "US", "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", - Network accessline 216
"applicableCountry": "US", "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", "merchantReturnDays": 30, - Network accessline 217
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow", - Network accessline 218
"merchantReturnDays": 30, "returnMethod": "https://schema.org/ReturnByMail", "returnFees": "https://schema.org/FreeReturn" - Network accessline 219
"returnMethod": "https://schema.org/ReturnByMail", - Network accessline 220
"returnFees": "https://schema.org/FreeReturn" - Network accessline 226
- Variants: `ProductGroup` with `hasVariant` and `variesBy` (size, color), each variant a `Product` with its own `sku`/`offers`; `productGroupID`. - Price ranges: `AggregateOffer` with `lowPrice`/`highPrice`/`offerCount`. - Sale prices: `pr - Network accessline 227
- Price ranges: `AggregateOffer` with `lowPrice`/`highPrice`/`offerCount`. - Sale prices: `priceSpecification` with `UnitPriceSpecification` and `priceType: https://schema.org/StrikethroughPrice` for the original price. - Shipping and retur - Network accessline 228
- Sale prices: `priceSpecification` with `UnitPriceSpecification` and `priceType: https://schema.org/StrikethroughPrice` for the original price. - Network accessline 229
- Shipping and return policy can be defined once at the Organization level (`hasMerchantReturnPolicy`, `shippingDetails` via `OfferShippingDetails` on Organization — supported since 2024/2025) instead of per offer, or configured in Merchant - Network accessline 244
"operatingSystem": "Web, iOS, Android", "offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" }, "url": "https://www.example.com/" - Network accessline 245
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" }, "url": "https://www.example.com/" } - Network accessline 246
"url": "https://www.example.com/" - Network accessline 259
{ "@type": "Dentist", "@id": "https://www.example.com/locations/leeds#localbusiness", - Network accessline 260
"@type": "Dentist", "@id": "https://www.example.com/locations/leeds#localbusiness", "name": "Bright Smile Dental Leeds", - Network accessline 261
"@id": "https://www.example.com/locations/leeds#localbusiness", - Network accessline 262
"name": "Bright Smile Dental Leeds", "image": "https://www.example.com/img/leeds-clinic.jpg", "url": "https://www.example.com/locations/leeds", - Network accessline 263
"image": "https://www.example.com/img/leeds-clinic.jpg", - Network accessline 264
"url": "https://www.example.com/locations/leeds", - Network accessline 276
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"], "opens": "08:30", "closes": "17:30" } ], "parentOrganization": { "@id": "https://www.example.com/#organization" } - Network accessline 277
], "parentOrganization": { "@id": "https://www.example.com/#organization" } } - Network accessline 278
"parentOrganization": { "@id": "https://www.example.com/#organization" } - Network accessline 292
"startDate": "2026-11-20T18:00:00+00:00", "endDate": "2026-11-20T21:00:00+00:00", "eventStatus": "https://schema.org/EventScheduled", - Network accessline 293
"endDate": "2026-11-20T21:00:00+00:00", "eventStatus": "https://schema.org/EventScheduled", "eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode", - Network accessline 294
"eventStatus": "https://schema.org/EventScheduled", - Network accessline 295
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode", - Network accessline 299
"address": { "@type": "PostalAddress", "streetAddress": "10 Example Rd", "addressLocality": "London", "postalCode": "E1 6AN", "addressCountry": "GB" } }, "image": ["https://www.example.com/img/event.jpg"], - Network accessline 300
}, "image": ["https://www.example.com/img/event.jpg"], "description": "An evening of talks on pricing, invoicing and tax for freelancers.", - Network accessline 301
"image": ["https://www.example.com/img/event.jpg"], - Network accessline 302
"description": "An evening of talks on pricing, invoicing and tax for freelancers.", "organizer": { "@type": "Organization", "name": "Acme", "url": "https://www.example.com/" }, "offers": { "@type": "Offer", "url": "https://www.example. - Network accessline 303
"organizer": { "@type": "Organization", "name": "Acme", "url": "https://www.example.com/" }, - Network accessline 304
"offers": { "@type": "Offer", "url": "https://www.example.com/events/ffl-2026", "price": "15.00", "priceCurrency": "GBP", "availability": "https://schema.org/InStock", "validFrom": "2026-09-01T00:00:00+00:00" } - Network accessline 344
"mainEntity": { "@type": "Person", "@id": "https://www.example.com/#person", - Network accessline 345
"@type": "Person", "@id": "https://www.example.com/#person", "name": "Jane Doe", - Network accessline 346
"@id": "https://www.example.com/#person", - Network accessline 349
"jobTitle": "Product Designer", "description": "Product designer specialising in fintech onboarding.", "image": "https://www.example.com/jane.jpg", - Network accessline 350
"description": "Product designer specialising in fintech onboarding.", "image": "https://www.example.com/jane.jpg", "url": "https://www.example.com/", - Network accessline 351
"image": "https://www.example.com/jane.jpg", - Network accessline 352
"url": "https://www.example.com/", - Network accessline 353
"sameAs": ["https://www.linkedin.com/in/janedoe", "https://github.com/janedoe"], - Network accessline 370
"name": "How to send your first invoice", "description": "A 3-minute walkthrough of creating and sending an invoice in Acme.", "thumbnailUrl": ["https://www.example.com/video/first-invoice.jpg"], - Network accessline 371
"description": "A 3-minute walkthrough of creating and sending an invoice in Acme.", "thumbnailUrl": ["https://www.example.com/video/first-invoice.jpg"], "uploadDate": "2026-05-01T09:00:00+00:00", - Network accessline 372
"thumbnailUrl": ["https://www.example.com/video/first-invoice.jpg"], - Network accessline 373
"uploadDate": "2026-05-01T09:00:00+00:00", "duration": "PT3M12S", "contentUrl": "https://cdn.example.com/video/first-invoice.mp4", - Network accessline 374
"duration": "PT3M12S", "contentUrl": "https://cdn.example.com/video/first-invoice.mp4", "embedUrl": "https://www.youtube.com/embed/XXXXXXXX" - Network accessline 375
"contentUrl": "https://cdn.example.com/video/first-invoice.mp4", - Network accessline 376
"embedUrl": "https://www.youtube.com/embed/XXXXXXXX" - Network accessline 388
"@type": "Recipe", "name": "Classic Jollof Rice", "image": ["https://www.example.com/img/jollof-16x9.jpg"], - Network accessline 389
"name": "Classic Jollof Rice", "image": ["https://www.example.com/img/jollof-16x9.jpg"], "author": { "@type": "Person", "name": "Jane Doe" }, - Network accessline 390
"image": ["https://www.example.com/img/jollof-16x9.jpg"], - Network accessline 420
Google retired the **Course info** rich result in 2025; the **Course list** (carousel) feature for course providers may still apply. `Course` with `name`, `description`, `provider` remains valid schema and useful for entity understanding. V
skills/ultimate-seo/references/technical-seo.md
- Network accessline 57
- Server-side (`301`/`308`) only. Avoid JS redirects and `<meta refresh>` (followed by Google but slower, lossy elsewhere). - 301 vs 308: equivalent for SEO; 308 preserves method (POST). Frameworks often default to 307/308 — fine. - **One h - Network accessline 58
- 301 vs 308: equivalent for SEO; 308 preserves method (POST). Frameworks often default to 307/308 — fine. - **One hop**: `http://example.com/a` → `https://www.example.com/a` directly, not via two hops. Chains > 5 hops are abandoned by Goog - Network accessline 59
- **One hop**: `http://example.com/a` → `https://www.example.com/a` directly, not via two hops. Chains > 5 hops are abandoned by Googlebot. - Network accessline 97
Sitemap: https://www.example.com/sitemap.xml - Network accessline 114
Test: Search Console robots.txt report; `curl -A Googlebot https://site/robots.txt`. - Network accessline 121
<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 122
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - Network accessline 123
<url> <loc>https://www.example.com/blog/late-payment-email</loc> <lastmod>2026-09-14</lastmod> - Network accessline 124
<loc>https://www.example.com/blog/late-payment-email</loc> - Network accessline 135
- Reference from robots.txt and submit in Search Console + Bing Webmaster Tools. - Extensions (separate namespaces): - **Image**: `xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"`, `<image:image><image:loc>…</image:loc></ima - Network accessline 136
- Extensions (separate namespaces): - **Image**: `xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"`, `<image:image><image:loc>…</image:loc></image:image>` — useful when images are lazy-loaded via JS or on CDN hosts. - **Vid - Network accessline 137
- **Image**: `xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"`, `<image:image><image:loc>…</image:loc></image:image>` — useful when images are lazy-loaded via JS or on CDN hosts. - Network accessline 138
- **Video**: `xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"`, requires `thumbnail_loc`, `title`, `description`, `content_loc` or `player_loc`. - Network accessline 139
- **News**: `xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"`; only articles from last 2 days, ≤1000 URLs; publisher name + language + publication_date + title. - Network accessline 140
- **hreflang**: `xmlns:xhtml="http://www.w3.org/1999/xhtml"` with `<xhtml:link rel="alternate" hreflang="…" href="…"/>` — see `international.md`. - Network accessline 142
Verify against current docs: https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap - Network accessline 190
CSR pitfalls checklist: - Empty `<div id="root">` in raw HTML → nothing for non-rendering crawlers. Check with `curl -s URL | grep -c '<h1'`. - Network accessline 191
- Empty `<div id="root">` in raw HTML → nothing for non-rendering crawlers. Check with `curl -s URL | grep -c '<h1'`. - Network accessline 237
Launch: - [ ] Deploy 301s (one hop), test the full map with a script (`curl -sI` each, expect 301 → 200). - Network accessline 238
- [ ] Deploy 301s (one hop), test the full map with a script (`curl -sI` each, expect 301 → 200). - Network accessline 279
1. Generate a key (8–128 hex chars), host it at `https://example.com/{key}.txt` containing the key. - Network accessline 283
POST https://api.indexnow.org/indexnow - Network accessline 286
{"host":"www.example.com","key":"<key>","keyLocation":"https://www.example.com/<key>.txt","urlList":["https://www.example.com/blog/new-post"]} - Network accessline 292
Verify against current docs: https://www.indexnow.org/documentation
skills/ultimate-seo/scripts/detect_stack.py
- Executable scriptline 1
#!/usr/bin/env python3
skills/ultimate-seo/scripts/generate_sitemap.py
- Executable scriptline 1
#!/usr/bin/env python3 - Network accessline 8
Examples: generate_sitemap.py public --base-url https://example.com - Network accessline 9
generate_sitemap.py public --base-url https://example.com - Network accessline 10
generate_sitemap.py dist --base-url https://example.com --lastmod git --no-trailing-slash - Network accessline 11
generate_sitemap.py _site --base-url https://example.com --stdout - Network accessline 87
def render_urlset(urls: List[Tuple[str, Optional[str]]]) -> str: lines = ['<?xml version="1.0" encoding="UTF-8"?>', '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'] - Network accessline 88
lines = ['<?xml version="1.0" encoding="UTF-8"?>', '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'] - Network accessline 95
def render_index(locs: List[str]) -> str: lines = ['<?xml version="1.0" encoding="UTF-8"?>', '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'] - Network accessline 96
lines = ['<?xml version="1.0" encoding="UTF-8"?>', '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'] - Network accessline 103
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("root", help="directory containing the built HTML") ap.add_argument("--base-url", required=True, help="productio - Network accessline 104
ap.add_argument("root", help="directory containing the built HTML") ap.add_argument("--base-url", required=True, help="production origin, e.g. https://www.example.com") ap.add_argument("--no-trailing-slash", action="store_true", hel - Network accessline 105
ap.add_argument("--base-url", required=True, help="production origin, e.g. https://www.example.com") - Network accessline 113
if not args.base_url.startswith(("http://", "https://")): ap.error("--base-url must be absolute, e.g. https://www.example.com") - Network accessline 114
ap.error("--base-url must be absolute, e.g. https://www.example.com")
skills/ultimate-seo/scripts/seo_audit.py
- Executable scriptline 1
#!/usr/bin/env python3 - Network accessline 4
Examples: seo_audit.py dist # audit a static build seo_audit.py http://localhost:3000 --crawl 50 # crawl a running dev server - Network accessline 5
seo_audit.py dist # audit a static build seo_audit.py http://localhost:3000 --crawl 50 # crawl a running dev server seo_audit.py https://example.com --json # machine-readable output - Network accessline 6
seo_audit.py http://localhost:3000 --crawl 50 # crawl a running dev server - Network accessline 7
seo_audit.py https://example.com --json # machine-readable output - Network accessline 8
seo_audit.py out --base-url https://example.com --fail-under 85 # CI gate - Network accessline 45
"description-duplicate": "Write unique descriptions per page, or generate them from page data.", "canonical-missing": "Add a self-referencing absolute <link rel=\"canonical\">.", "canonical-relative": "Canonical URLs must be absolut - Network accessline 46
"canonical-missing": "Add a self-referencing absolute <link rel=\"canonical\">.", "canonical-relative": "Canonical URLs must be absolute (https://…), built from one site-origin config.", "canonical-multiple": "Emit exactly one canon - Network accessline 47
"canonical-relative": "Canonical URLs must be absolute (https://…), built from one site-origin config.", - Network accessline 78
"robots-missing": "Add /robots.txt that allows crawling and references your sitemap.", "robots-blocks-all": "robots.txt blocks the whole site for all crawlers. Remove `Disallow: /` before launch.", "robots-no-sitemap": "Reference th - Network accessline 79
"robots-blocks-all": "robots.txt blocks the whole site for all crawlers. Remove `Disallow: /` before launch.", "robots-no-sitemap": "Reference the sitemap in robots.txt: `Sitemap: https://…/sitemap.xml`.", "robots-blocks-assets": "D - Network accessline 80
"robots-no-sitemap": "Reference the sitemap in robots.txt: `Sitemap: https://…/sitemap.xml`.", - Network accessline 364
continue seen.add(key) res = fetch(url, timeout) - Network accessline 365
seen.add(key) res = fetch(url, timeout) if res.status and "html" not in res.content_type.lower() and res.status < 400: - Network accessline 366
res = fetch(url, timeout) - Network accessline 381
extras: Dict[str, Optional[str]] = {} for name in ("robots.txt", "sitemap.xml", "llms.txt"): res = fetch(f"{origin}/{name}", timeout) - Network accessline 382
for name in ("robots.txt", "sitemap.xml", "llms.txt"): res = fetch(f"{origin}/{name}", timeout) extras[name] = res.body if res.status == 200 else None - Network accessline 383
res = fetch(f"{origin}/{name}", timeout) - Network accessline 385
if extras.get("sitemap.xml") is None and extras.get("robots.txt"): for kind, value in parse_robots(extras["robots.txt"] or "").get("__sitemaps__", []): res = fetch(value, timeout) - Network accessline 386
for kind, value in parse_robots(extras["robots.txt"] or "").get("__sitemaps__", []): res = fetch(value, timeout) if res.status == 200: - Network accessline 387
res = fetch(value, timeout) - Network accessline 601
ap.add_argument("target", help="URL, build directory, or single HTML file") ap.add_argument("--crawl", type=int, default=25, help="max pages to crawl in URL mode (default 25)") ap.add_argument("--base-url", help="production origin f - Network accessline 602
ap.add_argument("--crawl", type=int, default=25, help="max pages to crawl in URL mode (default 25)") ap.add_argument("--base-url", help="production origin for directory/file mode, e.g. https://example.com") ap.add_argument("--json", - Network accessline 603
ap.add_argument("--base-url", help="production origin for directory/file mode, e.g. https://example.com")
skills/ultimate-seo/scripts/seo_lib.py
- Executable scriptline 1
Executable file - Network accessline 227
def fetch(url: str, timeout: float = 15.0) -> FetchResult: - Network accessline 228
req = urllib.request.Request(url, headers={"User-Agent": USER_AGENT, "Accept": "text/html,*/*;q=0.8"}) - Network accessline 229
try: with urllib.request.urlopen(req, timeout=timeout) as resp: raw = resp.read(5_000_000) - Network accessline 230
with urllib.request.urlopen(req, timeout=timeout) as resp:
skills/ultimate-seo/scripts/validate_jsonld.py
- Executable scriptline 1
#!/usr/bin/env python3 - Network accessline 4
Examples: validate_jsonld.py dist # every HTML file in a build validate_jsonld.py https://example.com/post # a live page - Network accessline 5
validate_jsonld.py dist # every HTML file in a build validate_jsonld.py https://example.com/post # a live page validate_jsonld.py page.html schema.json # files (.html or raw .json) - Network accessline 6
validate_jsonld.py https://example.com/post # a live page - Network accessline 10
This is a fast offline linter, not a replacement for Google's Rich Results Test (https://search.google.com/test/rich-results). It catches the mistakes - Network accessline 11
Test (https://search.google.com/test/rich-results). It catches the mistakes - Network accessline 29
# type -> (required, recommended). "a|b" means at least one of them. # Based on Google Search Central structured data docs; re-check # https://developers.google.com/search/docs/appearance/structured-data/search-gallery when updating. - Network accessline 31
# https://developers.google.com/search/docs/appearance/structured-data/search-gallery when updating. - Network accessline 126
ctx = node.get("@context") if ctx is None: out.append(Finding("error", source, path, "Missing @context (use \"https://schema.org\")")) - Network accessline 127
if ctx is None: out.append(Finding("error", source, path, "Missing @context (use \"https://schema.org\")")) elif isinstance(ctx, str) and "schema.org" not in ctx: - Network accessline 128
out.append(Finding("error", source, path, "Missing @context (use \"https://schema.org\")")) - Network accessline 173
avail = node.get("availability") if isinstance(avail, str) and not AVAILABILITY.match(avail): out.append(Finding("warning", source, here, f"availability should be a schema.org URL like https://schema.org/InStock: - Network accessline 174
if isinstance(avail, str) and not AVAILABILITY.match(avail): out.append(Finding("warning", source, here, f"availability should be a schema.org URL like https://schema.org/InStock: {avail!r}")) if canon == "Breadcrumb - Network accessline 175
out.append(Finding("warning", source, here, f"availability should be a schema.org URL like https://schema.org/InStock: {avail!r}")) - Network accessline 218
for t in targets: if is_url(t): res = fetch(t) - Network accessline 219
if is_url(t): res = fetch(t) if res.error or res.status >= 400: - Network accessline 220
res = fetch(t)
How the signals fit together
Facts from a static read of the files at the pinned commit. They describe what the code does, not why.
Some files could not be read; the facts below still hold.
Signal confidence: 500 facts
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:38Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:50Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:51Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:90Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:91Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:92Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:117Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:118Low confidence
- Network access in prose of the SKILL.mdultimate-seo/SKILL.md:119Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:14Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:58Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:59Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:60Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:73Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:74Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:75Low confidence
- Network access in prose of documentationultimate-seo/assets/ULTIMATE-SEO.template.md:76Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:9Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:10Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:11Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:15Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:16Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:20Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:21Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:25Low confidence
- Network access in prose of documentationultimate-seo/assets/llms.txt:26Low confidence
- Network access in prose of documentationultimate-seo/assets/robots.txt:1Low confidence
- Network access in prose of documentationultimate-seo/assets/robots.txt:2Low confidence
- Network access in prose of documentationultimate-seo/assets/robots.txt:32Low confidence
- Executable script in code of a file that runsultimate-seo/evals/audit-only-no-code-changes/files/astro.config.mjs:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/audit-only-no-code-changes/files/package.json:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/audit-only-no-code-changes/place-files.sh:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/files/app/about/page.tsx:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/files/app/blog/[slug]/page.tsx:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/files/app/blog/page.tsx:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/files/app/layout.tsx:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/files/app/page.tsx:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/files/lib/posts.ts:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/files/package.json:1High confidence
- Network access in prose of documentationultimate-seo/evals/nextjs-blog-full-setup/graders/01-metadata-base-and-template.md:7Low confidence
- Executable script in code of a file that runsultimate-seo/evals/nextjs-blog-full-setup/place-files.sh:1High confidence
- Network access in prose of documentationultimate-seo/evals/nextjs-blog-full-setup/prompt.md:8Low confidence
- Network access in prose of documentationultimate-seo/evals/static-html-local-bakery/graders/01-unique-heads.md:7Low confidence
- Executable script in code of a file that runsultimate-seo/evals/static-html-local-bakery/place-files.sh:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/vite-react-spa-landing/files/package.json:1High confidence
- Executable script in code of a file that runsultimate-seo/evals/vite-react-spa-landing/files/src/App.tsx:1High confidence
- Network access in code of a file that runsultimate-seo/evals/vite-react-spa-landing/files/src/App.tsx:10High confidence
- Network access in code of a file that runsultimate-seo/evals/vite-react-spa-landing/files/src/App.tsx:11High confidence
- Network access in code of a file that runsultimate-seo/evals/vite-react-spa-landing/files/src/App.tsx:12High confidence
- Executable script in code of a file that runsultimate-seo/evals/vite-react-spa-landing/files/src/main.tsx:1High confidence
and 450 more
Only the first 500 facts are listed.
Works with
| Agent | Status | Evidence | Install to |
|---|---|---|---|
| Claude Code | Native | Manifest .claude-plugin/marketplace.json | .claude/skills/<skill-name>/ |
| Codex | Compatible | Standard SKILL.md skills/ultimate-seo/SKILL.md | .agents/skills/<skill-name>/ |
| Cursor | Compatible | Standard SKILL.md skills/ultimate-seo/SKILL.md | .cursor/skills/<skill-name>/ |
| Gemini CLI | Compatible | Standard SKILL.md skills/ultimate-seo/SKILL.md | .gemini/skills/<skill-name>/ |
| GitHub Copilot | Compatible | Standard SKILL.md skills/ultimate-seo/SKILL.md | .github/skills/<skill-name>/ |
| OpenCode | Compatible | Standard SKILL.md skills/ultimate-seo/SKILL.md | .opencode/skills/<skill-name>/ |
- Native The repository ships a manifest, folder or frontmatter field for this agent.
- Compatible A standard SKILL.md that this agent can read.
- Unknown No evidence either way.
Derived automatically from paths, manifests and frontmatter. Not tested on each agent.