🔍 Herramienta Análisis SEO
SaaS de análisis SEO con IA para optimizar contenido web.
📋 Contexto
Las herramientas SEO existentes son complejas. Esta solución ofrece análisis instantáneo con sugerencias de IA.
🎯 Objetivo
Construir SaaS que permita:
- Analizar contenido HTML/URL
- Calcular métricas SEO (densidad, legibilidad)
- Generar sugerencias con OpenAI
- Historial de análisis por usuario
📦 Alcance
Incluye:
- Análisis SEO automático
- Puntuación 0-100
- Sugerencias IA
- Dashboard con historial
Stack:
- Next.js 14 + TypeScript
- Tailwind + shadcn/ui
- Clerk Auth
- Neon PostgreSQL + Prisma
- OpenAI API
🏛️ Arquitectura
Estructura
/app
/api
/analyze/route.ts
/ai-suggestions/route.ts
/dashboard/page.tsx
/analyze/page.tsx
/components
/analysis-form.tsx
/seo-results.tsx
/ai-suggestions.tsx
/lib
/seo-analyzer.ts
/readability.ts
/openai.ts
🗄️ Base de Datos
Schema Prisma
model User {
id String @id @default(cuid())
clerkId String @unique
email String @unique
trialEndsAt DateTime?
isPro Boolean @default(false)
analyses Analysis[]
}
model Analysis {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
content String @db.Text
keyword String
url String?
// Métricas
wordCount Int
keywordDensity Float
readabilityScore Float
seoScore Int
// Estructura
hasH1 Boolean
h1Text String?
headings Json // {h2: [], h3: []}
images Int
imagesWithoutAlt Int
internalLinks Int
externalLinks Int
// Meta
metaTitle String?
metaDescription String?
aiSuggestions Json?
createdAt DateTime @default(now())
@@index([userId])
}
🔍 Lógica SEO
Analyzer Core
interface SEOAnalysis {
wordCount: number;
keywordDensity: number;
hasH1: boolean;
h1Text: string | null;
headings: { h2: string[]; h3: string[] };
images: number;
imagesWithoutAlt: number;
internalLinks: number;
externalLinks: number;
keywordInTitle: boolean;
keywordInFirst150: boolean;
seoScore: number;
}
export function analyzeSEO(html: string, keyword: string): SEOAnalysis {
const doc = new DOMParser().parseFromString(html, "text/html");
const text = doc.body.textContent || "";
const words = text
.toLowerCase()
.split(/\s+/)
.filter(w => w.length > 0);
const keywordLower = keyword.toLowerCase();
const keywordCount = words.filter(w => w.includes(keywordLower)).length;
// Cálculo de score
let score = 0;
if (words.length >= 800) score += 20;
if (keywordDensity >= 0.5 && keywordDensity <= 2.5) score += 20;
if (h1) score += 15;
if (keywordInH1) score += 15;
return {
/* ... */
};
}
🎯 Score SEO
| Factor | Peso | Condición |
|---|---|---|
| Longitud contenido | 20% | ≥800 palabras |
| Densidad keyword | 20% | 0.5% - 2.5% |
| H1 presente | 15% | Debe existir |
| Keyword en H1 | 15% | Coincidencia |
| Keyword en primer 150 chars | 10% | Posición inicial |
| Imágenes con alt | 10% | 100% cobertura |
| Links externos | 10% | >0 |
✅ Checklist Implementación
- Schema Prisma creado
- Migraciones aplicadas
- API /analyze funcionando
- Score calculado correctamente
- UI con shadcn/ui
- Clerk auth integrado
- OpenAI sugerencias