indxel
npx skills add https://github.com/indxel/indxel-skill --skill indxel
Agent 安装分布
Skill 文档
Indxel â SEO infrastructure for developers
You are an expert in using the indxel npm package and CLI to set up bulletproof SEO in Next.js projects. Indxel is “ESLint for SEO” â it validates metadata at build time so broken SEO never ships to production.
Knowledge Base: Before making SEO recommendations, consult references/seo-knowledge-base.md for the complete set of SEO best practices, critical rules, structured data patterns (@graph, sameAs), GEO optimization (AI-readiness, semantic HTML, llms.txt), rendering strategies, and Core Web Vitals thresholds. This ensures your advice goes beyond tool usage and reflects what actually matters for ranking in 2026.
Before Starting
Check if indxel is already set up:
- Look for
seo.config.ts(orseo.config.js) at the project root - Check if
indxelis inpackage.jsondependencies - Check if pages already use
createMetadata()orgenerateMetadata()
If not set up, start with initialization. If already set up, skip to the relevant section.
1. Installation & Init
Install the package
npm install indxel
Initialize the project
npx indxel init
This generates:
seo.config.tsâ Global SEO configurationapp/sitemap.tsâ Dynamic sitemapapp/robots.tsâ robots.txt configurationpublic/<key>.txtâ IndexNow verification key
With git hook guard:
npx indxel init --hook
2. defineSEO() â Global Configuration
Create seo.config.ts at the project root:
import { defineSEO } from 'indxel'
export default defineSEO({
siteName: 'MonSaaS',
siteUrl: 'https://monsaas.fr',
titleTemplate: '%s | MonSaaS',
defaultOGImage: '/og-default.png',
locale: 'fr_FR',
twitter: {
handle: '@monsaas',
cardType: 'summary_large_image',
},
organization: {
name: 'MonSaaS',
logo: 'https://monsaas.fr/logo.png',
url: 'https://monsaas.fr',
},
verification: {
google: 'google-site-verification-code',
},
})
SEOConfig fields
| Field | Type | Required | Description |
|---|---|---|---|
siteName |
string |
Yes | Display name (titles, structured data) |
siteUrl |
string |
Yes | Canonical base URL (no trailing slash) |
defaultTitle |
string |
No | Fallback page title |
titleTemplate |
string |
No | Template with %s placeholder |
defaultOGImage |
string |
No | Default OG image URL |
locale |
string |
No | Locale (e.g. fr_FR, en_US) |
twitter |
object |
No | { handle, cardType } |
organization |
object |
No | { name, logo, url } |
verification |
object |
No | { google?, yandex?, bing? } |
3. createMetadata() â Per-Page Metadata
In each page.tsx or layout.tsx, export metadata using createMetadata():
import { createMetadata } from 'indxel'
import seoConfig from '@/seo.config'
export function generateMetadata() {
return createMetadata({
title: 'Pricing',
description: 'Simple, transparent pricing. Start free.',
path: '/pricing',
}, seoConfig)
}
PageSEO fields
| Field | Type | Required | Description |
|---|---|---|---|
title |
string |
Yes | Page title |
description |
string |
Yes | Meta description |
path |
string |
Yes | URL path (e.g. /blog/my-post) |
ogImage |
string |
No | Override default OG image |
noindex |
boolean |
No | Add noindex directive |
canonical |
string |
No | Override canonical URL |
alternates |
Record<string, string> |
No | hreflang alternates |
article |
object |
No | Article metadata (publishedTime, author, tags) |
structuredData |
array |
No | JSON-LD entries for this page |
Article pages
export function generateMetadata() {
return createMetadata({
title: 'How to Fix Broken Meta Tags',
description: 'A guide to catching SEO regressions before they ship.',
path: '/blog/fix-broken-meta-tags',
ogImage: '/blog/fix-broken-meta-tags/og.png',
article: {
publishedTime: '2026-01-15',
author: 'Jane Doe',
section: 'Engineering',
tags: ['SEO', 'Next.js', 'CI/CD'],
},
}, seoConfig)
}
Multilingual pages
export function generateMetadata() {
return createMetadata({
title: 'Accueil',
description: 'Infrastructure SEO pour developpeurs.',
path: '/fr',
alternates: {
en: '/en',
fr: '/fr',
de: '/de',
},
}, seoConfig)
}
4. generateLD() â Structured Data (JSON-LD)
Generate type-safe JSON-LD for rich results:
import { generateLD } from 'indxel'
// In your component or page:
const faqLD = generateLD('FAQ', {
questions: [
{ question: 'What is indxel?', answer: 'ESLint for SEO.' },
{ question: 'Is it free?', answer: 'The CLI and SDK are open-source.' },
],
})
// Render:
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqLD) }}
/>
Supported types
| Type | Key fields | Use case |
|---|---|---|
Article |
headline, datePublished, author |
Blog posts |
Product |
name, price, currency, brand |
Product pages |
FAQ |
questions: [{ question, answer }] |
FAQ sections |
HowTo |
name, steps: [{ name, text }] |
Tutorials |
Breadcrumb |
items: [{ name, url }] |
Navigation breadcrumbs |
Organization |
name, url, logo |
About pages |
WebPage |
name, description, url |
Generic pages |
SoftwareApplication |
name, category, price |
App/tool pages |
WebSite |
name, url, searchUrl |
Site-level schema |
Examples
Product:
generateLD('Product', {
name: 'Indxel Pro',
description: 'SEO monitoring dashboard.',
price: '19',
currency: 'EUR',
brand: 'Indxel',
url: 'https://indxel.com/pricing',
})
Breadcrumb:
generateLD('Breadcrumb', {
items: [
{ name: 'Home', url: 'https://indxel.com' },
{ name: 'Blog', url: 'https://indxel.com/blog' },
{ name: 'Post Title', url: 'https://indxel.com/blog/post' },
],
})
HowTo:
generateLD('HowTo', {
name: 'Set up indxel in 3 steps',
steps: [
{ name: 'Install', text: 'Run npm install indxel' },
{ name: 'Init', text: 'Run npx indxel init' },
{ name: 'Check', text: 'Run npx indxel check' },
],
})
5. validateMetadata() â Programmatic Validation
Validate metadata in code (used internally by the CLI):
import { createMetadata, validateMetadata } from 'indxel'
import seoConfig from '@/seo.config'
const metadata = createMetadata({
title: 'Home',
description: 'Welcome.',
path: '/',
}, seoConfig)
const result = validateMetadata(metadata)
console.log(result.score) // 85
console.log(result.grade) // "B"
console.log(result.errors) // [{ id: 'og-image', message: '...' }]
Options
validateMetadata(metadata, {
strict: true, // Treat warnings as errors
disabledRules: ['alternates'], // Skip specific rules
})
6. CLI â npx indxel check
Basic check
npx indxel check
Scans all page.tsx files, extracts static metadata, validates against 17 rules, outputs a score per page.
CI/CD mode
npx indxel check --ci
Strict mode. Exit code 1 on any error. Use in GitHub Actions or Vercel build.
Diff mode
npx indxel check --diff
Compare with previous run. Shows score changes per page.
Minimum score
npx indxel check --min-score 80
Fail only if average score drops below threshold.
Fix suggestions
npx indxel check --fix
Show code snippets to fix detected errors.
JSON output
npx indxel check --json
Machine-readable output for integrations.
7. Validation Rules (17 rules, 100 points)
| Rule | Points | Severity | What it checks |
|---|---|---|---|
title-present |
5 | critical | Page has a title |
title-length |
10 | optional | Title is 30-60 characters |
description-present |
5 | critical | Page has meta description |
description-length |
10 | optional | Description is 120-160 chars |
og-image |
10 | optional | Open Graph image is set |
og-title |
5 | optional | OG title is set |
og-description |
5 | optional | OG description is set |
canonical |
10 | critical | Canonical URL is set |
structured-data-present |
8 | optional | Has JSON-LD |
structured-data-valid |
2 | optional | JSON-LD is valid |
structured-data-complete |
5 | optional | JSON-LD has required fields |
robots |
5 | optional | Robots directives present |
twitter-card |
5 | optional | Twitter card is configured |
alternates |
5 | optional | hreflang alternates set |
viewport |
3 | optional | Viewport meta present |
favicon |
2 | optional | Favicon exists |
image-alt |
5 | optional | Images have alt text |
Scoring:
- Pass = full points
- Warning = half points
- Error = 0 points
- Grade: A (90+), B (80+), C (70+), D (60+), F (<60)
8. CI/CD Integration
GitHub Actions
# .github/workflows/seo.yml
name: SEO Check
on: [push, pull_request]
jobs:
seo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx indxel check --ci
Vercel Build
In package.json:
{
"scripts": {
"build": "npx indxel check --ci && next build"
}
}
Git pre-push hook
npx indxel init --hook
Blocks git push if critical SEO errors are found.
9. Configuration File
Create .indxelrc.json at the project root for persistent CLI settings:
{
"minScore": 80,
"disabledRules": ["alternates"],
"ignoreRoutes": ["/dashboard/*", "/api/*"],
"baseUrl": "https://monsaas.fr"
}
Verification
After making changes, always verify:
- Run the check:
npx indxel check - Confirm score is acceptable: Look for grade A or B (80+)
- No critical errors: Title, description, and canonical must pass
- Structured data present: Pages should have relevant JSON-LD
If errors remain, read the error messages â they tell you exactly what’s missing and what to add.
Common Patterns
Layout metadata (shared across routes)
// app/blog/layout.tsx
import { createMetadata } from 'indxel'
import seoConfig from '@/seo.config'
export function generateMetadata() {
return createMetadata({
title: 'Blog',
description: 'Engineering insights and product updates.',
path: '/blog',
}, seoConfig)
}
Dynamic pages (from CMS/database)
// app/blog/[slug]/page.tsx
import { createMetadata, generateLD } from 'indxel'
import seoConfig from '@/seo.config'
export async function generateMetadata({ params }) {
const post = await getPost(params.slug)
return createMetadata({
title: post.title,
description: post.excerpt,
path: `/blog/${post.slug}`,
ogImage: post.coverImage,
article: {
publishedTime: post.publishedAt,
author: post.author.name,
tags: post.tags,
},
}, seoConfig)
}
noindex for authenticated pages
export function generateMetadata() {
return createMetadata({
title: 'Dashboard',
description: 'Your SEO dashboard.',
path: '/dashboard',
noindex: true,
}, seoConfig)
}
Beyond Metadata â SEO Best Practices
The indxel CLI catches metadata issues. But good SEO goes further. When
reviewing or setting up a project, also check these (see references/seo-knowledge-base.md for full details):
-
Semantic HTML â Use
<article>,<section>,<nav>, not div soup. AI crawlers rely on semantic tags to understand content relationships. -
Heading hierarchy â One
<h1>per page, no skipped levels (H2âH4). -
Structured data strategy â Use the
@graphpattern to connect entities. Every Organization needssameAslinking to LinkedIn, Wikipedia, etc. -
GEO readiness â Add
/llms.txtfor AI discoverability. Check thatrobots.txtdoesn’t block GPTBot, ClaudeBot, or Google-Extended. -
Rendering â Public pages must use SSG/ISR/SSR. Pure CSR = invisible to crawlers. Check for
'use client'on SEO-critical pages. -
Inverted pyramid â The answer must come right after the heading. AI models weight the first 100-200 tokens of a section heavily.
-
Performance â LCP < 2.5s, INP < 200ms, CLS < 0.1. Check for heavy imports, unoptimized images, render-blocking scripts.