Tech behind the tool: el stack tecnológico de SEOJuice

Vadim Kravcenko
Vadim Kravcenko
· Updated · 5 min read

Cuando me propuse construir SEOJuice, la primera decisión realmente importante no fue una funcionalidad ni un modelo de precios. Fue una pregunta a la que volvía una y otra vez: ¿uso la tecnología que ya conozco o la que se ve impresionante en un post de "How We Built It"? Elegí lo aburrido. Y lo volvería a hacer, porque una tecnología aburrida que entiendes a fondo le gana, cada vez, a una tecnología de moda que vas aprendiendo sobre la marcha. (Pregúntame por las tres semanas que perdí evaluando una base de datos de grafos antes de admitir que PostgreSQL podía hacer todo lo que necesitaba.)

Este artículo ofrece una visión transparente de cada capa de la infraestructura de SEOJuice: no solo las decisiones finales, sino también los compromisos que implicaron. Si eres fundador y estás evaluando tu propio stack, espero que el razonamiento te resulte más útil que las etiquetas.

Filosofía del stack tecnológico de SEOJuice

Mi filosofía se resume en tres reglas que aprendí por las malas después de años sacando adelante proyectos paralelos antes de SEOJuice:

A high-quality stock photo showing a technical professional analyzing data or AI-driven processing on a laptop or workstation, visually matching the section about processing pipelines and AI systems.
A high-quality stock photo showing a technical professional analyzing data or AI-driven processing on a laptop or workstation, visually matching the section about processing pipelines and AI systems.. Source: Semrush Blog
A realistic photo of a developer building or maintaining backend infrastructure, with code on screens and a professional workspace that supports the article's discussion of pragmatic stack decisions, Django, ASGI, and Nginx.
A realistic photo of a developer building or maintaining backend infrastructure, with code on screens and a professional workspace that supports the article's discussion of pragmatic stack decisions, Django, ASGI, and Nginx.. Source: Semrush Blog

Regla 1: controla el camino crítico. Si la funcionalidad central de tu producto depende de una API de terceros, le acabas de dar a otra empresa la capacidad de dejarte fuera de juego. El motor de rastreo de SEOJuice, el análisis de enlaces y los algoritmos de puntuación corren sobre infraestructura que yo controlo. En el momento en que subcontratas tu diferenciador principal, dejas de ser un producto y te conviertes en un revendedor.

Regla 2: elige tecnologías que puedas depurar a las 2 AM. Consideré FastAPI para el back-end. Es más rápido en pruebas comparativas, más moderno y su enfoque asíncrono está mejor resuelto. Pero llevo escribiendo Django desde 2016. Cuando Sentry dispara una alerta a medianoche, no quiero pasarme 40 minutos leyendo documentación; quiero saber exactamente qué middleware está fallando. La familiaridad no es pereza; es madurez operativa.

Regla 3: minimiza las piezas móviles. Cada servicio adicional en tu arquitectura es otra cosa que puede fallar, otra cosa que necesita supervisión, otra dependencia que actualizar. Yo cuento los servicios en mi archivo docker-compose como un mochilero cuenta gramos.

Stack de back-end

En el corazón de SEOJuice está Django. Lo elegí por encima de Flask (demasiado básico para un producto así de complejo), FastAPI (excelente para APIs, pero yo necesitaba el admin de Django, su ORM y su motor de plantillas) y Rails (no conozco Ruby lo suficientemente bien como para depurarlo a ciegas). La filosofía de Django de venir con "baterías incluidas" hizo que no me pasara los primeros tres meses armando un sistema de autenticación, un panel de administración y un framework de migraciones a partir de paquetes separados. La contrapartida es que Django puede sentirse pesado para microservicios simples, pero SEOJuice no es un microservicio simple. Es un monolito con más de 15 apps, y Django maneja eso bastante bien.

La aplicación corre sobre ASGI con Uvicorn, detrás de Nginx como proxy inverso. Cambié de Gunicorn (WSGI) a Uvicorn aproximadamente al año, cuando añadí soporte para WebSocket para notificaciones en tiempo real y el servidor MCP. Esa migración fue sorprendentemente indolora, uno de los beneficios de la adopción gradual de ASGI en Django. Cloudflare está delante de todo, encargándose del DNS, la terminación SSL y la protección contra DDoS. He visto a Cloudflare absorber picos de tráfico que habrían tumbado mis servidores sin problemas.

Todos los servidores funcionan con Linux y están alojados en Hetzner. ¿Por qué Hetzner y no AWS? Honestamente, por costo. Un servidor dedicado de Hetzner con 64 GB de RAM cuesta más o menos lo que una instancia equivalente de EC2 cuesta por una semana. Para un producto autofinanciado, esa diferencia importa muchísimo. La contrapartida es menos automatización: no hay auto-scaling, no hay Kubernetes administrado. Yo manejo los despliegues con Docker y algunos scripts de shell. No es vistoso, pero funciona, y el dinero que ahorro va directo al desarrollo del producto.

La base de datos es PostgreSQL con la extensión pgvector. Evalué MongoDB al principio (todo el mundo lo estaba usando en 2022) y enseguida me di cuenta de que los datos SEO son profundamente relacionales: las páginas pertenecen a sitios web, las keywords pertenecen a páginas, los enlaces conectan páginas entre sí. Una base de datos documental me habría obligado a reimplementar la mitad de lo que Postgres ya ofrece de serie. La extensión pgvector fue lo que terminó de convencerme: me permite almacenar y consultar vectores de embeddings directamente junto a los datos relacionales, lo que hace posible la detección de similitud entre contenidos y las funciones de AI sin necesidad de una base de datos vectorial separada.

Para tareas en segundo plano, uso Celery con Redis como broker. Celery recibe muchas críticas en la comunidad Python, y parte de ellas son merecidas: la documentación está dispersa, las opciones de configuración son abrumadoras y depurar fallos en tareas puede ser desesperante. Pero no he encontrado nada mejor para el enorme volumen de tareas en segundo plano que hace SEOJuice: rastrear miles de páginas, ejecutar análisis NLP, generar reportes, supervisar backlinks. Consideré Dramatiq y Huey como alternativas más ligeras. Dramatiq es realmente bueno, pero el ecosistema de Celery (programador beat, monitoreo con Flower, django-celery-results) terminó ganando.

La autenticación pasa por Auth0. Construí un sistema de autenticación personalizado para un proyecto anterior y pasé una cantidad vergonzosa de tiempo lidiando con casos límite de restablecimiento de contraseñas, limitación de tasa y flujos de MFA. Auth0 se encarga de todo eso. El costo escala con los usuarios, lo cual duele en ciertos umbrales, pero el tiempo de ingeniería que ahorra vale varias veces la suscripción.

Todo corre en contenedores Docker. Mi entorno de desarrollo y el de producción usan contenedores idénticos. Eso eliminó una clase entera de bugs de "en mi máquina sí funciona" que perseguían mis proyectos anteriores. Sentry supervisa excepciones en tiempo real: puedo rastrear un bug reportado por un usuario desde su sesión hasta la línea exacta de código en menos de un minuto.

Stack de front-end

Decidí deliberadamente evitar React, Vue y cualquier otro framework de JavaScript. El panel de SEOJuice es HTML renderizado en servidor con Tailwind CSS y Alpine.js para la interactividad. Esta es la decisión que más objeciones me genera de otros desarrolladores, y entiendo por qué: se siente como construir con herramientas manuales cuando existen herramientas eléctricas.

Esta es mi lógica: SEOJuice es un panel cargado de datos. Los usuarios miran tablas, gráficos y reportes. No necesitan edición colaborativa en tiempo real ni una gestión compleja del estado del lado del cliente. El renderizado en servidor significa que cada carga de página es rápida, la carga inicial es pequeña y no tengo que mantener un proceso de compilación del front-end por separado, una capa de API adicional ni una librería para gestionar el estado. Alpine.js se encarga de los menús desplegables, modales y filtros interactivos. En los pocos lugares donde necesito una interactividad más rica (el panel de supervisión en tiempo real), uso htmx para intercambiar fragmentos de HTML sin recargar la página completa.

Los archivos estáticos se sirven a través del CDN de Bunny.net. Probé el CDN de Cloudflare (que ya uso para DNS), pero encontré que el precio por request de Bunny era más predecible para mis patrones de tráfico. La diferencia es marginal; cualquiera de los dos funcionaría.

Procesamiento e AI

Una parte importante de lo que hace útil a SEOJuice es procesar grandes volúmenes de datos y usar AI para funciones que sería imposible construir manualmente.

Para modelos de lenguaje, me integro con OpenAI y Claude. Uso modelos distintos para tareas distintas basándome en meses de pruebas: GPT-4o para extracción de datos estructurados (sigue esquemas JSON con más fiabilidad), Claude para análisis y sugerencias de contenido (escribe de forma más natural y maneja mejor los matices). Probé ejecutar modelos open-source localmente —Llama 2 y luego Llama 3— y la brecha de calidad para uso en producción seguía siendo demasiado grande como para justificar el costo de infraestructura. Ese cálculo cambia cada pocos meses, así que lo reviso con regularidad.

Uso pgvector para búsqueda por embeddings en lugar de una base de datos vectorial dedicada como Pinecone o Weaviate. Tener los vectores en PostgreSQL junto con el resto de los datos significa que puedo combinar resultados de similitud de embeddings con consultas relacionales en una sola sentencia SQL. El rendimiento es suficiente para nuestra escala. Si estuviera manejando miles de millones de vectores, necesitaría algo especializado. Con millones, Postgres lo resuelve sin problema.

En el lado de NLP, NumPy, NLTK y Scikit-learn hacen el trabajo pesado para extracción de keywords, puntuación de contenido y clasificación. Estas librerías no son emocionantes, pero están probadas en batalla. Cuando corro un análisis TF-IDF sobre 50,000 páginas, necesito que el resultado sea correcto, no innovador.

Para rastrear sitios cargados de JavaScript, uso Playwright corriendo en un contenedor separado. Consume más recursos que simples solicitudes HTTP, pero los sitios modernos muchas veces renderizan contenido crítico vía JavaScript. Si nuestro crawler no puede verlo, no podemos analizarlo. Playwright maneja SPAs, contenido lazy-loaded y client-side routing que sería invisible para un crawler tradicional.

Herramientas y servicios adicionales

La infraestructura de soporte es donde más dispuesto he estado a usar servicios de terceros, porque nada de esto es un diferenciador central:

Crisp para chat en vivo. Probé Intercom primero: era demasiado caro y demasiado complejo para un equipo de soporte de una sola persona. Crisp hace lo que necesito por una fracción del costo.

Customer.io para email. Los correos transaccionales (restablecimiento de contraseña, entrega de reportes), las secuencias de onboarding y las actualizaciones de producto corren a través de Customer.io. Cambié desde una configuración más simple (el email integrado de Django con SendGrid) porque necesitaba disparadores basados en comportamiento: "envía un email con un tip si el usuario no ha conectado su sitio de WordPress en 3 días".

Paddle para pagos. Empecé con Stripe y migré a Paddle como Merchant of Record. La razón fue totalmente práctica: Paddle se encarga del cálculo, cobro y remisión del VAT para todos los países. Como fundador europeo autofinanciado vendiendo globalmente, construir mi propio sistema de cumplimiento fiscal habría sido un trabajo de tiempo completo. Paddle se queda con una comisión mayor que Stripe, pero elimina una categoría entera de carga operativa.

ChartMogul para analítica de ingresos. MRR, churn rate, LTV, expansion revenue: necesito que estos números sean precisos y se actualicen automáticamente. Podría calcularlos a partir de la API de Paddle, pero ChartMogul lo hace mejor y además muestra tendencias que probablemente ni se me ocurriría revisar.

Para analítica de visitantes, corro una instancia self-hosted de Plausible. Sin cookies, sin banners de consentimiento, sin enviar datos de visitantes a Google. Me muestra fuentes de tráfico, páginas principales y referrers, que sinceramente es todo lo que necesito. (Escribí sobre Plausible con más detalle en nuestra guía de herramientas SEO open-source.)

Qué cambiaría

Ninguna tecnología es perfecta, y ya aprendí lo suficiente como para saber qué haría distinto si empezara desde cero:

Invertiría antes en Kubernetes. No el día uno —eso sería excesivo para un MVP—, pero sí alrededor del momento en que llegué a 10 workers en segundo plano. Orquestar contenedores con scripts de shell y systemd funciona... hasta que deja de funcionar, y la transición hacia una orquestación de verdad mientras sirves tráfico de producción pone los nervios de punta.

Separaría la API del monolito antes. Tener el panel, la API pública, la API del plugin de WordPress y el servidor MCP compartiendo un solo proceso de Django significa que un pico de tráfico en la API puede ralentizar el panel. Poco a poco los estoy extrayendo a servicios separados, pero habría sido más limpio diseñarlo así desde el principio.

No cambiaría las decisiones centrales: Django, PostgreSQL, Celery y HTML renderizado en servidor. Han demostrado su valor durante dos años de tráfico en producción, y la simplicidad que aportan vale más que las ganancias de rendimiento que podría obtener con alternativas más de moda.

Conclusión

Como fundador en solitario, la trampa más peligrosa es construir tu stack para la audiencia de Hacker News en vez de para las necesidades reales de tu producto. Cada decisión tecnológica que describí aquí estuvo impulsada por una necesidad específica, evaluada frente a alternativas y elegida porque me permitía lanzar más rápido y con menos sorpresas. El resultado es un sistema que puedo operar yo solo, depurar rápido y extender sin tener que reescribirlo.

Pero esto apenas empieza. La tecnología evoluciona a medida que evoluciona el producto: estoy trabajando continuamente para mejorar SEOJuice, y la infraestructura tiene que seguirle el ritmo. Si eres fundador y estás tomando estas mismas decisiones, espero que ver el razonamiento detrás de las mías te ahorre parte del ensayo y error por el que yo pasé.

Sigamos construyendo.

Saludos,
Vadim

Lecturas relacionadas:

SEOJuice
Stay visible everywhere
Get discovered across Google and AI platforms with research-based optimizations.
Works with any CMS
Automated Internal Links
On-Page SEO Optimizations
Get Started Free

no credit card required

More articles

No related articles found.