SvelteKit integration for Capyseo with Vite plugin and dev-time server hooks.
Documentation Β· GitHub Β· Report Issue
Part of the Capyseo toolkit.
Deep SvelteKit integration for the Capyseo SEO analyzer. Get real-time SEO feedback during development and enforce SEO quality in your CI/CD pipeline.
While you can use the CLI to analyze any built site, this package provides SvelteKit-specific integrations that make SEO analysis seamless:
# Using npm
npm install @capyseo/sveltekit @capyseo/core
# Using Bun (recommended)
bun add @capyseo/sveltekit @capyseo/core
# Using pnpm
pnpm add @capyseo/sveltekit @capyseo/core
Add the Vite plugin to analyze pages during vite build:
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { capyseo } from '@capyseo/sveltekit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit(),
capyseo(),
],
});
Now when you run vite build, you'll see SEO analysis for each page.
Add server hooks to see SEO issues in real-time as you browse your dev server:
// src/hooks.server.ts
import { createCapyseoHandle } from '@capyseo/sveltekit/hooks';
export const handle = createCapyseoHandle();
Now visit any page on http://localhost:5173 and check your terminal for SEO feedback.
The Vite plugin analyzes your pages during vite build. This is ideal for:
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { capyseo } from '@capyseo/sveltekit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit(),
capyseo({
// Options here
}),
],
});
Perfect for CI/CDβprevent deploying sites with SEO issues:
capyseo({
// Fail build if any page scores below 80
minScore: 80,
// Fail build if there are any SEO errors
failOnError: true,
})
Skip pages that don't need SEO analysis:
capyseo({
exclude: [
'/admin/*', // Admin pages
'/api/*', // API routes
'/preview/*', // Preview pages
'/__data.json', // SvelteKit data endpoints
],
})
Get AI-generated meta descriptions and alt text:
capyseo({
// Using environment variable
geminiApiKey: process.env.GEMINI_API_KEY,
// Or specify the provider
aiProvider: 'openai',
aiApiKey: process.env.OPENAI_API_KEY,
})
Process analysis results programmatically:
capyseo({
onReport: (reports) => {
// Calculate average score
const avg = reports.reduce((sum, r) => sum + r.score, 0) / reports.length;
console.log(`Average SEO score: ${avg.toFixed(1)}/100`);
// Find worst pages
const worst = reports.filter(r => r.score < 70);
if (worst.length > 0) {
console.log('Pages needing attention:', worst.map(r => r.url));
}
// Write custom report
fs.writeFileSync('seo-summary.json', JSON.stringify({
averageScore: avg,
totalPages: reports.length,
issueCount: reports.reduce((sum, r) => sum + r.issues.length, 0),
}));
},
})
interface VitePluginOptions {
// Enable/disable analysis (defaults to true in dev)
analyze?: boolean;
// Minimum score to pass build (0-100)
minScore?: number;
// Fail build on any SEO errors
failOnError?: boolean;
// Paths to exclude from analysis (glob patterns)
exclude?: string[];
// AI provider: 'openai' | 'anthropic' | 'gemini' | 'ollama'
aiProvider?: string;
// API key for AI provider
aiApiKey?: string;
geminiApiKey?: string; // Shorthand for Gemini
// Ollama base URL (default: http://localhost:11434)
ollamaBaseUrl?: string;
// Custom report handler
onReport?: (reports: Report[]) => void;
}
Server hooks analyze pages in real-time as you develop. This is ideal for:
// src/hooks.server.ts
import { createCapyseoHandle } from '@capyseo/sveltekit/hooks';
export const handle = createCapyseoHandle();
Using SvelteKit's sequence helper:
// src/hooks.server.ts
import { sequence } from '@sveltejs/kit/hooks';
import { createCapyseoHandle } from '@capyseo/sveltekit/hooks';
const capyseoHandle = createCapyseoHandle({
logLevel: 'issues',
});
const authHandle = async ({ event, resolve }) => {
// Your auth logic
return resolve(event);
};
export const handle = sequence(capyseoHandle, authHandle);
Control how much output you see:
createCapyseoHandle({
// 'none' β No output
// 'issues' β Only pages with SEO issues (default)
// 'all' β Every page analyzed
logLevel: 'issues',
})
Example output with logLevel: 'issues':
[capyseo] /about (Score: 72/100)
β [meta-description] Missing meta description
! [open-graph] Missing og:image
createCapyseoHandle({
enabled: process.env.NODE_ENV === 'development',
})
Process results programmatically:
createCapyseoHandle({
onReport: (report) => {
// Send to monitoring service
if (report.score < 70) {
console.warn(`β οΈ Low SEO score on ${report.url}: ${report.score}/100`);
}
// Track specific issues
const missingMeta = report.issues.filter(i =>
i.rule === 'meta-description' || i.rule === 'meta-title'
);
if (missingMeta.length > 0) {
console.warn('Missing meta tags:', missingMeta);
}
},
})
interface HooksOptions {
// Enable/disable analysis (defaults to true in dev)
enabled?: boolean;
// Log level: 'none' | 'issues' | 'all'
logLevel?: 'none' | 'issues' | 'all';
// Paths to exclude from analysis (glob patterns)
exclude?: string[];
// AI provider settings
aiProvider?: string;
aiApiKey?: string;
// Custom report handler (called for each page)
onReport?: (report: Report) => void;
}
Both the Vite plugin and server hooks support AI-powered suggestions. When enabled, Capyseo will:
// vite.config.ts
capyseo({
aiProvider: 'openai',
aiApiKey: process.env.OPENAI_API_KEY,
})
capyseo({
aiProvider: 'anthropic',
aiApiKey: process.env.ANTHROPIC_API_KEY,
})
capyseo({
aiProvider: 'gemini',
aiApiKey: process.env.GEMINI_API_KEY,
// Or use the shorthand:
geminiApiKey: process.env.GEMINI_API_KEY,
})
Run AI locally without API keys:
ollama pull llama3.3capyseo({
aiProvider: 'ollama',
// Optional: custom URL if not running locally
ollamaBaseUrl: 'http://localhost:11434',
})
Recommended models by hardware:
| Hardware | Model Command |
|---|---|
| RTX 4090 (24GB) | ollama pull deepseek-r1:70b |
| RTX 4070 (12GB) | ollama pull qwen3-coder:14b |
| M4 Pro (48GB) | ollama pull deepseek-r1:70b |
| M4 (16GB) | ollama pull qwen3-coder:14b |
| CPU only | ollama pull phi-3:3.8b |
The plugins automatically read these environment variables:
| Variable | Description |
|---|---|
OPENAI_API_KEY |
OpenAI API key |
ANTHROPIC_API_KEY |
Anthropic API key |
GEMINI_API_KEY |
Google Gemini API key |
OLLAMA_BASE_URL |
Ollama server URL (default: http://localhost:11434) |
For best results, ensure your SvelteKit config outputs prerendered HTML:
// svelte.config.js
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter({
fallback: 'index.html',
}),
prerender: {
entries: ['*'], // Prerender all pages
},
},
};
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { capyseo } from '@capyseo/sveltekit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit(), capyseo()],
});
// src/hooks.server.ts
import { createCapyseoHandle } from '@capyseo/sveltekit/hooks';
export const handle = createCapyseoHandle();
# .github/workflows/seo.yml
name: SEO Check
on: [push, pull_request]
jobs:
seo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run build
env:
# Build will fail if score < 80
# (configured in vite.config.ts with minScore: 80)
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { capyseo } from '@capyseo/sveltekit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit(),
capyseo({
// Strict requirements for production
minScore: 85,
failOnError: true,
// Exclude non-public routes
exclude: ['/admin/*', '/api/*', '/__*'],
// AI suggestions in CI
aiProvider: 'gemini',
aiApiKey: process.env.GEMINI_API_KEY,
// Custom reporting
onReport: (reports) => {
// Write report for deployment review
const summary = {
date: new Date().toISOString(),
averageScore: reports.reduce((s, r) => s + r.score, 0) / reports.length,
pageCount: reports.length,
errorCount: reports.flatMap(r => r.issues).filter(i => i.severity === 'error').length,
};
fs.writeFileSync('seo-report.json', JSON.stringify(summary, null, 2));
},
}),
],
});
Make sure you're building with prerendering enabled:
// svelte.config.js
export default {
kit: {
prerender: {
entries: ['*'],
},
},
};
src/hooks.server.ts (not src/hooks.ts)handle:export const handle = createCapyseoHandle();
Verify your API key is set:
echo $OPENAI_API_KEY
Check you specified the provider:
capyseo({
aiProvider: 'openai',
aiApiKey: process.env.OPENAI_API_KEY,
})
If minScore is set and pages don't meet it, the build will fail. Either:
capyseo({ minScore: 70 })
capyseo({ exclude: ['/draft/*'] })
| Package | Description |
|---|---|
| @capyseo/core | Core analysis engine (for custom integrations) |
| @capyseo/cli | Command-line interface (for any site) |
See CONTRIBUTING.md for development setup and guidelines.
To report vulnerabilities, see SECURITY.md.
MIT Β© Capyseo