Instala el paquete de Node.js
Instala el paquete de SEO Core, configura el middleware y la sincronización, y verifica la entrega server-side en tu aplicación Node.js.
Qué hace
El paquete @seo-core-app-ai/node-deploy se integra en tu servidor Node.js como middleware. Mantiene una copia local actualizada de tus deployments activos y los aplica a cada respuesta HTML antes de enviarla al cliente. Los cambios que haces en el dashboard se propagan automáticamente al servidor, sin reiniciar la app, sin rebuild y sin pipeline de deployment.
Renderizado server-side
Los deployments se aplican en el HTML antes de que salga del servidor, visibles para crawlers y navegadores sin depender de JavaScript.
Push sync en tiempo real
Registra la URL de webhook de tu servidor y los nuevos deployments llegan a tu app en menos de 3 segundos después de guardarlos en el dashboard.
Polling automático de respaldo
Incluso sin webhook registrado, el paquete revisa cambios cada 30 segundos para mantener los deployments actualizados sin importar tu infraestructura.
Actualizaciones sin reinicio
La caché de deployments se actualiza en segundo plano. Tu aplicación sigue sirviendo tráfico sin downtime ni reinicios.
Requisitos
- Node.js 18 o posterior.
- Un proyecto de SEO Core con dominio verificado y deploy token.
- Tu servidor debe poder hacer requests HTTPS salientes a la API de SEO Core.
- Para push sync en tiempo real: tu servidor debe ser accesible públicamente por HTTPS.
Instalación
- 1
Instala el paquete
npm install @seo-core-app-ai/node-deploy - 2
Agrega tus credenciales como variables de entorno
Encuentra tu Project ID y Deploy Token en el dashboard bajo Projects → Deploy Script → Node.js. Agrégalos a tu entorno:
SEO_DEPLOY_PROJECT_ID=your_project_id SEO_DEPLOY_TOKEN=your_deploy_tokenImportante
Nunca hardcodees tu deploy token en archivos fuente. Usa variables de entorno para mantener el token fuera del control de versiones.
- 3
Inicializa el cliente al arrancar
Crea un cliente singleton, normalmente en un archivo compartido como
lib/seo-client.ts, y llamainitialize()una vez cuando el servidor arranca:import { SeoDeployClient } from "@seo-core-app-ai/node-deploy"; export const seoClient = new SeoDeployClient({ projectId: parseInt(process.env.SEO_DEPLOY_PROJECT_ID!), token: process.env.SEO_DEPLOY_TOKEN!, }); await seoClient.initialize();Consejo
Llama
initialize()antes de que el servidor empiece a aceptar requests para que la caché de deployments esté lista desde el primer request.
Integración con Express
Agrega el middleware antes de tus route handlers. Intercepta automáticamente respuestas HTML y aplica cualquier deployment activo para la URL solicitada.
import express from "express";
import { createExpressMiddleware } from "@seo-core-app-ai/node-deploy/express";
import { seoClient } from "./lib/seo-client";
const app = express();
// Add before your routes
app.use(createExpressMiddleware(seoClient));
app.get("/", (req, res) => {
res.send("<html><head><title>My Site</title></head>...</html>");
// The middleware patches the title if a deployment is active for this URL
});
app.listen(3000);Nota
El middleware solo modifica respuestas con header Content-Type: text/html. JSON, imágenes y otros tipos de respuesta pasan sin cambios.
Integración con Fastify
Registra el plugin en tu instancia de Fastify. Usa un lifecycle hook para modificar respuestas HTML antes de enviarlas.
import Fastify from "fastify";
import { seoDeployPlugin } from "@seo-core-app-ai/node-deploy/fastify";
import { seoClient } from "./lib/seo-client";
const app = Fastify();
await app.register(seoDeployPlugin, { client: seoClient });
app.get("/", async () => {
return "<html><head><title>My Site</title></head>...</html>";
});
await app.listen({ port: 3000 });Integración con Next.js (App Router)
El paquete incluye un server component listo llamado SeoDeployHead. Agrégalo una vez a tu root layout y no tendrás que cambiar páginas individuales. Inyecta title, description y canonical directamente en el HTML de cada request.
1. Crea un cliente singleton
Crea lib/seo-deploy-client.ts para mantener una instancia compartida que persista entre hot reloads en desarrollo:
// lib/seo-deploy-client.ts
import { SeoDeployClient } from "@seo-core-app-ai/node-deploy";
declare global { var _seoDeployClient: SeoDeployClient | undefined; }
if (!global._seoDeployClient) {
global._seoDeployClient = new SeoDeployClient({
projectId: parseInt(process.env.SEO_DEPLOY_PROJECT_ID!),
token: process.env.SEO_DEPLOY_TOKEN!,
});
global._seoDeployClient.initialize().catch(console.error);
}
export const seoDeployClient = global._seoDeployClient;2. Pasa el pathname vía middleware
SeoDeployHead necesita saber qué página se está renderizando. Agrega una línea a tu middleware.ts para reenviar el pathname como request header:
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(req: NextRequest) {
const res = NextResponse.next();
res.headers.set("x-seo-core-pathname", req.nextUrl.pathname);
return res;
}
export const config = { matcher: ["/((?!_next|favicon.ico).*)"] };Nota
Si ya tienes un middleware.ts, solo agrega la línea res.headers.set. No necesitas otro middleware.
3. Agrega SeoDeployHead a tu root layout
Este es el único cambio necesario en tu app. Todas las páginas reciben deployments automáticamente sin código por página.
// app/layout.tsx
import { SeoDeployHead } from "@seo-core-app-ai/node-deploy/nextjs/head";
import { seoDeployClient } from "@/lib/seo-deploy-client";
export default function RootLayout({ children }) {
return (
<html>
<head>
{/* Applies active deployments — title, description, canonical */}
<SeoDeployHead client={seoDeployClient} />
</head>
<body>{children}</body>
</html>
);
}Consejo
SeoDeployHead devuelve null cuando no hay deployments activos para la URL actual, así que no hay costo de rendimiento en páginas sin deployments.
4. Configura variables de entorno
SEO_DEPLOY_PROJECT_ID=your_project_id
SEO_DEPLOY_TOKEN=your_deploy_tokenImportante
Nunca hagas commit de tu deploy token. Usa variables de entorno.
Push sync en tiempo real (opcional)
Por defecto, el cliente revisa cambios de deployments cada 30 segundos. Push sync es opcional: entrega cambios a tu servidor en el momento en que los guardas en el dashboard (menos de 3 segundos), en vez de esperar el siguiente polling.
Express y Fastify manejan el webhook de push automáticamente. Los usuarios de Next.js pueden agregar opcionalmente un route handler:
// app/seo-core/sync/route.ts
import { seoDeployClient } from "@/lib/seo-deploy-client";
import { handleNextjsPushSync } from "@seo-core-app-ai/node-deploy/nextjs";
export async function POST(req: Request) {
return handleNextjsPushSync(req, seoDeployClient);
}Después registra https://your-site.com/seo-core/sync como webhook URL en Projects → Deploy Script → Node.js → Push sync webhook.
Nota
Si tu servidor está detrás de una red privada y push sync no es accesible, el paquete vuelve a polling automáticamente. Puedes ajustar el intervalo con pollIntervalMs o ponerlo en 0 para desactivar polling por completo.
Opciones de configuración
new SeoDeployClient({
projectId: 123, // Required. Your project ID.
token: "your_token", // Required. Keep in environment variables.
apiOrigin: "https://www.seocoreapp.com/api", // Optional. Override API base URL.
pollIntervalMs: 30_000, // Optional. Background poll interval. Set 0 to disable.
heartbeatIntervalMs: 60_000, // Optional. Lightweight freshness check interval.
webhookPath: "/seo-core/sync",// Optional. Path where your server receives push sync.
publicUrl: "https://your-site.com", // Optional. Enables auto-registration of push sync webhook.
deploymentTypes: ["title", "description"], // Optional. Limit which types apply.
onError: (err) => console.error(err), // Optional. Error callback.
});Entornos serverless
Importante
Las funciones serverless (Vercel Functions, AWS Lambda) no mantienen memoria persistente entre invocaciones. El cliente trae deployments en cada cold start y los reutiliza en invocaciones warm durante la vida de esa función. Usa pollIntervalMs: 0 para evitar timers en segundo plano innecesarios en contextos serverless.
Para compartir estado entre varias invocaciones serverless, el cliente soporta una interfaz cacheAdapter personalizada que puedes respaldar con Redis, Upstash o cualquier key-value store.
