Server Hooks Setup
The Capyseo server hook provides runtime SEO analysis for SvelteKit.
Installation
npm install -D @capyseo/adapter-sveltekit
Basic Setup
Create or update src/hooks.server.ts:
import { createCapyseoHandle } from '@capyseo/adapter-sveltekit/hooks';
export const handle = createCapyseoHandle();
Configuration
export const handle = createCapyseoHandle({
// Enable (default: true in dev)
enabled: process.env.NODE_ENV === 'development',
// Logging level
logLevel: 'issues', // 'none' | 'issues' | 'all'
// Paths to exclude
exclude: ['/admin/*', '/api/*'],
// Gemini API key
geminiApiKey: process.env.GEMINI_API_KEY,
// Custom report handler
onReport: (report) => {
console.log(`${report.url}: ${report.score}/100`);
},
});
Options
| Option |
Type |
Default |
Description |
enabled |
boolean |
true in dev |
Enable analysis |
logLevel |
string |
'issues' |
Logging verbosity |
exclude |
string[] |
- |
Paths to skip |
geminiApiKey |
string |
env var |
AI API key |
onReport |
function |
- |
Custom handler |
Log Levels
| Level |
Behavior |
'none' |
Silent |
'issues' |
Log pages with problems |
'all' |
Log every page |
Combining with Other Hooks
Use sequence to combine hooks:
import { sequence } from '@sveltejs/kit/hooks';
import { createCapyseoHandle } from '@capyseo/adapter-sveltekit/hooks';
const capyseoHandle = createCapyseoHandle({
logLevel: 'issues',
});
const authHandle = async ({ event, resolve }) => {
// Your auth logic
return resolve(event);
};
export const handle = sequence(authHandle, capyseoHandle);
Custom Report Handler
Process reports programmatically:
import { createCapyseoHandle } from '@capyseo/adapter-sveltekit/hooks';
export const handle = createCapyseoHandle({
onReport: async (report) => {
// Log to external service
if (report.score < 80) {
await fetch('https://monitoring.example.com/seo', {
method: 'POST',
body: JSON.stringify({
url: report.url,
score: report.score,
issues: report.issues.length,
}),
});
}
// Store in database
// await db.seoReports.create({ data: report });
// Alert on critical issues
const errors = report.issues.filter(i => i.severity === 'error');
if (errors.length > 0) {
console.error(`SEO errors on ${report.url}:`, errors);
}
},
});
Report Structure
interface SEOReport {
url: string;
timestamp: string;
score: number;
issues: Array<{
ruleId: string;
severity: 'error' | 'warning' | 'info';
message: string;
suggestion?: string;
}>;
}
Path Exclusion
createCapyseoHandle({
exclude: [
'/admin/*', // Admin pages
'/api/*', // API routes
'/auth/*', // Auth routes
'/_app/*', // SvelteKit internals
'/__data.json', // Data requests
],
});
Production Usage
For production monitoring:
export const handle = createCapyseoHandle({
// Enable in production
enabled: true,
// Only log issues
logLevel: 'issues',
// Send to monitoring
onReport: async (report) => {
if (report.score < 70) {
await sendAlert(`Low SEO score: ${report.url}`);
}
},
});
Performance
The hook is designed to be non-intrusive:
- Clones response - Original stream unaffected
- Async analysis - Doesn't block response
- No modification - Response unchanged
- Error resilient - Failures don't break app
Console Output
[capyseo] Analyzing /about...
[capyseo] /about - Score: 85/100
x [meta-description] Missing meta description
! [heading-hierarchy] Skipped heading level
[capyseo] Analyzing /blog...
[capyseo] /blog - Score: 92/100
i [open-graph] Missing og:image
Development vs Production
const isDev = process.env.NODE_ENV === 'development';
export const handle = createCapyseoHandle({
// Verbose in dev, minimal in prod
logLevel: isDev ? 'all' : 'none',
// Custom handler for prod
onReport: isDev ? undefined : sendToMonitoring,
});
Troubleshooting
Hook Not Running
Check hooks.server.ts location (must be in src/).
No Output
Check logLevel:
createCapyseoHandle({ logLevel: 'all' })
Performance Issues
Exclude heavy paths:
createCapyseoHandle({
exclude: ['/api/*', '/large-page'],
})