SEO Core
ExpressFastifyNext.jsServer-sideTiempo real

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. 1

    Instala el paquete

    npm install @seo-core-app-ai/node-deploy
  2. 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_token

    Importante

    Nunca hardcodees tu deploy token en archivos fuente. Usa variables de entorno para mantener el token fuera del control de versiones.

  3. 3

    Inicializa el cliente al arrancar

    Crea un cliente singleton, normalmente en un archivo compartido como lib/seo-client.ts, y llama initialize() 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_token

Importante

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.