Install
$ agentstack add skill-mvstepanek-nextjs-ecommerce-seo-skills-seo-crawlability ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Crawlability & Indexing SEO Guidelines
Follow these rules to ensure search engines can discover, crawl, and index all important pages on the site.
For current robots.txt and sitemap structure details, see [reference.md](reference.md).
robots.txt
Example e-commerce robots.txt (adapt paths to your project):
User-agent: *
Disallow: /*/search/
Disallow: /*/search
Sitemap: ${SITE_URL}/sitemap.xml
robots.txt vs noindex
- robots.txt blocks crawling, not indexing — Google may still index a blocked URL (with no snippet) if external sites link to it
- Use robots.txt only for pages that generate massive URL combinations — search results are the primary example, as they create near-infinite crawlable URLs that waste crawl budget
- Use
noindexfor finite pages that shouldn't be indexed — cart, checkout, account, wishlist, login, register. These have minimal crawl budget impact, andnoindexproperly prevents indexing
Rules for Modifying robots.txt
- Always reference the sitemap —
Sitemap:directive pointing to your sitemap URL - Keep robots.txt minimal — only block pages that genuinely waste crawl budget (e.g. search results with infinite URL combinations)
- Prefer
noindexover robots.txt for pages you want to prevent from appearing in search results —noindexis the correct tool for preventing indexing - Never block CSS/JS files — search engines need these to render pages
- Never block product or category pages — these are the pages you want ranked
- Test changes — use Google Search Console's robots.txt tester before deploying
In Next.js, you can generate robots.txt dynamically (App Router example; for Pages Router, use public/robots.txt or an API route):
// robots.ts (App Router) — for Pages Router, use public/robots.txt or an API route
import { MetadataRoute } from 'next';
// Example import — use your project's actual config
import { siteConfig } from '@/config/site';
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
disallow: ['/*/search/', '/*/search'],
},
sitemap: `${siteConfig.url}/sitemap_index.xml`,
};
}
Noindex Directives
Use noindex on pages that should be crawlable but NOT appear in search results:
| Page Type | Directive | Reason | |-----------|-----------|--------| | Search results | noindex, follow | Infinite URL combinations, thin content | | Granular filter combinations | noindex, follow | Thin/duplicate content — but keep useful single-filter pages (e.g. ?type=wireless) indexable if they match real search intent | | User account pages | noindex, nofollow | Private, no SEO value | | Cart / Checkout | noindex, nofollow | Private, no SEO value | | Thank you / confirmation | noindex, nofollow | No SEO value | | Internal error pages | noindex, nofollow | No SEO value | | Login / Register | noindex, follow | No SEO value, but follow links | | Print views | noindex, nofollow | Duplicate of main page |
Implementation:
// In page metadata
export const metadata: Metadata = {
robots: {
index: false,
follow: true, // or false depending on page type
},
};
// In generateMetadata for dynamic pages
export async function generateMetadata(): Promise {
return {
robots: { index: false, follow: true },
};
}
Important: Use noindex in the metadata, not in robots.txt. robots.txt blocks crawling entirely (search engines can't even see the noindex tag), while noindex allows crawling but prevents indexing.
XML Sitemaps
Sitemap Rules
- Only include canonical, indexable URLs — no noindex pages, no non-canonical URLs, no paginated URLs (except if self-canonical)
- Include all locale variants — every page in every locale it's available in
- Use
lastmod— accurate last modified date helps search engines prioritize crawling - Include hreflang in sitemaps — use `` (see seo-hreflang skill)
- Max 50,000 URLs per sitemap — split into sub-sitemaps if needed
- Max 50MB per sitemap file — monitor file sizes
- Keep sitemaps fresh — regenerate on content changes, not just at build time
Next.js sitemap generation (App Router example; for Pages Router, use an API route or build-time generation):
// sitemap.ts (App Router) — for Pages Router, generate via API route or at build time
import { MetadataRoute } from 'next';
// Example imports — use your project's actual config
import { siteConfig, ALL_LOCALES } from '@/config/site';
export default async function sitemap(): Promise {
const products = await getAllProducts();
return products.flatMap(product =>
ALL_LOCALES.map(locale => ({
url: `${siteConfig.url}/${locale}/products/${product.id}/${product.slug}`,
lastModified: product.updatedAt,
alternates: {
languages: Object.fromEntries(
ALL_LOCALES.map(loc => [loc, `${siteConfig.url}/${loc}/products/${product.id}/${product.slug}`])
),
},
}))
);
}
Note: Google ignores changeFrequency and priority fields in sitemaps — omit them. The lastmod field is the only optional field Google uses, and only when it's consistently accurate and reflects significant content changes.
Server-Side Rendering for SEO
- Critical content must be server-rendered — product names, descriptions, prices, specs
- Google can render JavaScript, but it introduces a delay (typically hours to days for initial indexing)
- Server-rendered content (Server Components in App Router, or
getServerSideProps/getStaticPropsin Pages Router) appears in the initial HTML — use this to your advantage - Never hide critical content behind client-side fetch — if a product name only appears after a
useEffectfetch, it may not be indexed promptly
// GOOD — content is in the initial HTML
export default async function ProductPage({ params }: Props) {
const product = await getProduct(params.id); // Server-side
return {product.name}; // In initial HTML
}
// BAD — content requires client-side JS to appear
"use client";
export default function ProductPage({ params }: Props) {
const [product, setProduct] = useState(null);
useEffect(() => { fetchProduct(params.id).then(setProduct); }, []);
return {product?.name}; // Not in initial HTML!
}
Orphan Pages
Every indexable page must be:
- Reachable from internal links — at least one link from another page on the site
- In the sitemap — listed in one of the XML sitemaps
- Not blocked by robots.txt — must be crawlable
If you create a new page, verify it has at least one internal link pointing to it (from navigation, category listing, related products, or footer).
Crawl Budget
For a large multi-locale site (many locales x many products), crawl budget matters:
- Don't waste it on non-valuable pages — noindex search, granular filter combos, account pages
- Use hreflang correctly — helps Google crawl locale variants efficiently
- Fresh sitemaps — helps Google prioritize changed pages
- Fast server response — slow responses waste crawl budget (aim for <500ms TTFB)
Common Mistakes to Avoid
- Using robots.txt to "hide" pages — use
noindexinstead; robots.txt prevents crawling, so Google can't see the noindex - Sitemap with non-canonical URLs — only canonical URLs belong in sitemaps
- Missing sitemap reference in robots.txt — always include
Sitemap:directive - Client-side rendered critical content — search engines may miss content that requires JS execution
- Orphan product pages — new products must be linked from category pages
- Stale sitemaps — regenerate when content changes, not just at deploy time
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mvstepanek
- Source: mvstepanek/nextjs-ecommerce-seo-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.