SDK
Validation
15 rules. 100 points. One score per page.
validateMetadata(metadata, options?)
Validate a metadata object against all 15 SEO rules. Returns a structured result with score, grade, and detailed findings.
Basic usagetypescript
import { validateMetadata } from 'indxel'
const result = validateMetadata({
title: 'Pricing — Simple plans for developers',
description: 'Start free. Upgrade when you need more.',
openGraph: {
title: 'Pricing',
description: 'Start free.',
images: [{ url: '/og-pricing.png' }],
},
twitter: { card: 'summary_large_image' },
alternates: { canonical: 'https://mysaas.com/pricing' },
})
console.log(result.score) // 85
console.log(result.grade) // 'B'
console.log(result.errors) // [{ id: 'description-length', message: '...', weight: 10 }]
console.log(result.warnings) // [{ id: 'alternates-hreflang', message: '...', weight: 5 }]
console.log(result.passed) // [{ id: 'title-present', ... }, ...]Strict mode
In strict mode, warnings are promoted to errors. Useful for CI/CD where you want zero tolerance.
typescript
const result = validateMetadata(metadata, { strict: true })
// Warnings now count as errors (weight = 0 instead of half)Return type
ValidationResulttypescript
type ValidationResult = {
score: number // 0-100
grade: string // 'A' | 'B' | 'C' | 'D' | 'F'
errors: RuleFinding[]
warnings: RuleFinding[]
passed: RuleFinding[]
}
type RuleFinding = {
id: string // Rule identifier (e.g. 'title-length')
message: string // Human-readable explanation
weight: number // Points this rule is worth
}Scoring Algorithm
Each rule has a weight. The total possible is 100 points.
- Pass — full weight awarded
- Warning — half weight awarded
- Error — 0 points
| Grade | Score |
|---|---|
| A | >= 90 |
| B | >= 80 |
| C | >= 70 |
| D | >= 60 |
| F | < 60 |
All 15 Rules
| Rule | Weight | Check |
|---|---|---|
| title-present | 5 | Page has a title tag |
| title-length | 10 | Title is 50-60 characters |
| description-present | 5 | Meta description exists |
| description-length | 10 | Description is 120-160 characters |
| og-image | 10 | OpenGraph image is set |
| og-title | 5 | OpenGraph title is set |
| og-description | 5 | OpenGraph description is set |
| canonical-url | 10 | Canonical URL present and absolute |
| structured-data-present | 10 | At least one JSON-LD block |
| structured-data-valid | 5 | JSON-LD has @context and @type |
| robots-not-blocking | 5 | Page not accidentally noindexed |
| twitter-card | 5 | Twitter card type configured |
| alternates-hreflang | 5 | Hreflang alternates declared |
| viewport-meta | 5 | Viewport meta tag present |
| favicon | 5 | Favicon referenced |
Total: 100 points
All weights sum to 100. A perfect score means every rule passes.
Using in CI/CD
The CLI's check --ci command uses validateMetadata() internally. For programmatic use in custom scripts:
Custom validation scripttypescript
import { validateMetadata } from 'indxel'
const result = validateMetadata(pageMetadata, { strict: true })
if (result.errors.length > 0) {
console.error(`SEO check failed: ${result.score}/100 (${result.grade})`)
result.errors.forEach(e => console.error(` ✗ ${e.id}: ${e.message}`))
process.exit(1)
}
console.log(`SEO check passed: ${result.score}/100 (${result.grade})`)