Codegea

Desarrollo

Desarrollo de software a medidaSistemas, plataformas e integraciones hechas a la medida de tu operaciónSitios corporativosProfesional, rápido y pensado para generar confianzaTiendas onlineCatálogo, pagos y envíos listos para vender las 24 horasWooCommerceTiendas WooCommerce rápidas, con pagos y factura de cada paísLanding pagesUna página enfocada en un solo objetivo: convertir visitantes en clientesApps móvilesApps iOS y Android a medida que ponen tu negocio en el bolsillo de tus clientes

Integración y CMS

Integraciones CMSWordPress, Strapi, Directus y Arc XP conectados a todo tu ecosistemaArc XPSoporte, implementación e integraciones para la plataforma de mediosMigracionesMigra tu sitio, plataforma o base de datos sin perder nada

Crecimiento e infraestructura

Automatización con IALa tecnología hace lo repetitivo y tu equipo se enfoca en lo que importaSEO on-pageQue Google te encuentre y te recomiende: optimización técnica y de contenidoServidores y hostingServidores rápidos y seguros, monitoreados 24/7
RetainerTu equipo dev, por mesDesde 20h al mes. Cuota fija.
Un cotizador con IA para cotizar servicios en minutosCotizaciones profesionales en minutos, con seguimiento de proyectos, vendedores y pagos en un solo lugar.Ver el caso

Por tipo

EcommerceTiendas y catálogosSitios corporativosMarca y captaciónPlataformas y appsSoftware a medida

Explorar

Todos los proyectosCasos y resultadosClientesQuién confía en nosotrosRetainerEquipo dev mensual

Blog

Todos los artículosGuías y opiniónBoletínUn correo al mesContactoRespondemos en 24h

Últimos artículos

Así está construido codegea.com: Next.js, Payload, Turso y R2CMS · 2026-10-20Cloudflare Workers: qué son y cuándo conviene usarlosNode.js · 2026-10-19Live Preview en Payload con Next.jsCMS · 2026-10-19
BoletínÚnete a nuestro boletínNotas prácticas de web, SEO e IA.
ServiciosDesarrollo de software a medidaSitios corporativosTiendas onlineWooCommerceLanding pagesApps móvilesIntegraciones CMSArc XPMigracionesAutomatización con IASEO on-pageServidores y hostingTu equipo dev, por mes
ProyectosCotizaciones profesionales en minutos, con seguimiento de proyectos, vendedores y pagos en un solo lugar.EcommerceSitios corporativosPlataformas y appsTodos los proyectosClientesRetainer
Retainer
BlogTodos los artículosBoletínContactoAsí está construido codegea.com: Next.js, Payload, Turso y R2Cloudflare Workers: qué son y cuándo conviene usarlosLive Preview en Payload con Next.jsÚnete a nuestro boletín
ESEN
Hablemos

CMS

Live Preview en Payload con Next.js

Cómo ver el artículo real mientras lo escribes en el panel de Payload: la URL de vista previa, una ruta que activa Draft Mode y un componente que refresca la página.

Derian Pinto · Founder & Full Stack Developer2026-10-192 min

Live Preview es la pantalla dividida del panel de Payload: a un lado el formulario, al otro tu sitio real mostrando el contenido que estás escribiendo. Para un editor es la diferencia entre publicar a ciegas y ver el resultado antes. Montarlo con Next.js son tres piezas pequeñas.

Cómo funciona

El panel carga tu sitio dentro de un iframe. Para que ese iframe muestre un borrador y no el contenido publicado, hay que pedirle a Next.js que active el Draft Mode. Cada vez que guardas, la página debe refrescarse. Las tres piezas:

  1. Una URL de vista previa en la configuración de Payload.
  2. Una ruta de API que comprueba tu sesión y activa Draft Mode.
  3. Un componente cliente en la página que refresca al guardar.

Pieza 1: la URL en la configuración

En payload.config.ts:

admin: {
  livePreview: {
    collections: ['posts', 'projects'],
    breakpoints: [
      { label: 'Móvil', name: 'mobile', width: 375, height: 667 },
      { label: 'Tablet', name: 'tablet', width: 768, height: 1024 },
      { label: 'Escritorio', name: 'desktop', width: 1440, height: 900 },
    ],
    url: ({ data, collectionConfig, locale }) => {
      if (!data?.slug || !collectionConfig) return null;
      const params = new URLSearchParams({
        collection: collectionConfig.slug,
        slug: String(data.slug),
        locale: locale.code,
      });
      return `/api/preview?${params}`;
    },
  },
},

La vista previa no apunta directo a la página del artículo, sino a una ruta intermedia, /api/preview, a la que le pasa la colección, el slug y el idioma. Si el documento aún no tiene slug, devuelve null y no hay vista previa. Los breakpoints añaden los botones de móvil, tablet y escritorio.

Pieza 2: la ruta que activa Draft Mode

En app/api/preview/route.ts:

export async function GET(req: NextRequest) {
  const params = req.nextUrl.searchParams;
  const draft = await draftMode();

  if (params.get('exit')) {
    draft.disable();
    redirect('/');
  }

  const payload = await payloadClient();
  const { user } = await payload.auth({ headers: req.headers });
  const collection = params.get('collection');
  const slug = params.get('slug');
  const locale = params.get('locale');

  if (!user || !slug || !isLocale(locale) ||
      (collection !== 'posts' && collection !== 'projects')) {
    return new Response('Forbidden', { status: 403 });
  }

  draft.enable();
  redirect(collection === 'posts' ? postPath(locale, slug) : projectPath(locale, slug));
}

Esta ruta exige sesión del panel. payload.auth({ headers }) comprueba la cookie, y como el iframe está en el mismo origen, la cookie viaja sola. Sin sesión, 403: nadie puede ver tus borradores adivinando la URL. Con sesión, activa Draft Mode y redirige a la URL real del artículo, construida con la misma función que usa el resto del sitio. ?exit=1 lo desactiva.

Pieza 3: la página lee borradores y se refresca

En la página del artículo, preguntas si Draft Mode está activo y se lo pasas a la consulta:

const { isEnabled: draft } = await draftMode();
const post = await getPost({ slug, locale, draft });
// …
{draft && <LivePreviewListener />}

Con draft en true, la consulta pide la última versión guardada como borrador, no la publicada. Y LivePreviewListener es un pequeño componente cliente:

'use client';

import { RefreshRouteOnSave } from '@payloadcms/live-preview-react';
import { useRouter } from 'next/navigation';

export function LivePreviewListener() {
  const router = useRouter();
  return <RefreshRouteOnSave refresh={() => router.refresh()} serverURL={SITE_URL} />;
}

Cada vez que se guarda en el panel, RefreshRouteOnSave llama a router.refresh() y Next.js vuelve a renderizar la página en el servidor, con el borrador nuevo.

Dos cosas que conviene saber

  • Refresca al guardar, no al teclear. Esta variante usa el refresco del servidor, que es la más simple y no exige que tu componente sepa leer datos en el cliente.
  • El panel y el sitio deben compartir origen. Si el panel está en otro dominio, la cookie de sesión no viaja en el iframe y hay que resolver la autenticación de otra manera.

Para qué sirve en la práctica

Quien escribe ve al instante cómo queda un título largo, una tabla o un bloque de código en móvil, sin publicar. Es una de las razones por las que elegimos Payload; el resto está en Payload vs Strapi vs Directus, y cómo encaja en el sitio, en así está construido codegea.com.

¿Compartir este artículo?LinkedInWhatsAppX

Escrito por

Derian Pinto

Founder & Full Stack Developer

Fundador de Codegea. Desarrolla sitios, tiendas y plataformas a medida, e integra y da soporte a Arc XP para medios.

Únete a nuestro boletín

Un correo con novedades y notas prácticas de web, SEO e IA. Sin spam, y te das de baja cuando quieras.

¿Montamos tu proyecto?

¿Necesitas ayuda? Chatea con nosotros