Cómo mostrar avances de blogs de HubSpot en una página de Webflow Cloud

Cómo mostrar avances de publicaciones de blog de HubSpot en una página de Webflow mediante API

Aprende a renderizar avances de blogs de HubSpot desde un Route Handler de Next.js en Webflow Cloud.

Cómo mostrar avances de publicaciones de blog de HubSpot en una página de Webflow mediante API

Ismail Ajagbe
Redactor técnico
Ver perfil del autor
Ismail Ajagbe
Redactor técnico
Ver perfil del autor
Índice de contenidos

Una pequeña aplicación de Webflow Cloud lee la API de HubSpot para mantener actualizados los avances del blog, así nadie tiene que actualizar la página de Webflow después de que el equipo de marketing publique cada nueva entrada.

Cuando el sitio de marketing funciona en Webflow y el blog en HubSpot, un bloque de "últimas entradas" suele implicar copiar a mano el título y el resumen de cada nueva publicación en el Designer, y el bloque queda desactualizado en cuanto alguien se olvida de hacerlo.

Webflow Cloud elimina esta tarea. Montas una aplicación de Next.js en una ruta de tu sitio de Webflow, le das un token de aplicación privada heredada de HubSpot como secreto y dejas que un Route Handler obtenga las publicaciones más recientes bajo demanda.

La página renderiza los avances en el servidor, por lo que el token permanece allí, y una página del Designer puede obtener los mismos datos mediante un embed de shortcode, en cualquier plan que permita publicar código personalizado.

¿Qué necesitas para mostrar avances de blogs de HubSpot en Webflow?

Necesitas cinco requisitos previos:

  • Sitio de Webflow con Webflow Cloud: Webflow Cloud viene incluido con el plan gratuito Starter y con todos los planes de pago, pero montar la aplicación en un dominio personalizado requiere el plan Premium o superior.
  • Acceso a aplicación privada de HubSpot: Una cuenta con al menos una entrada de blog publicada, además de permisos para crear aplicaciones privadas o un administrador que pueda crear una y entregarte el token.
  • Node.js y npm: Una versión de Node.js compatible con Webflow Cloud instalada localmente, con npm configurado como gestor de paquetes.
  • Proyecto con Next.js 15+ App Router: Webflow Cloud es compatible con Next.js 15 o superior; utiliza el App Router para la estructura, ya que los Route Handlers y los React Server Components lo requieren.
  • Repositorio conectado: El repositorio que conectas al proyecto de Webflow Cloud, de donde proviene el código. Mantén el token fuera de él; el token vive en el entorno de Webflow Cloud.

Con estas piezas listas, la construcción depende de mantener el token en el lado del servidor e incluir la ruta de montaje inyectada en las solicitudes del navegador.

6 pasos para mostrar avances de blogs de HubSpot en Webflow Cloud

La construcción consta de seis pasos, desde la creación de un token restringido de HubSpot hasta el despliegue de la aplicación y la incrustación de su salida. Valida cada resultado antes de continuar para que puedas aislar fácilmente cualquier error de configuración.

Empieza con la credencial, luego construye y despliega las dos rutas de acceso renderizadas en el servidor.

1. Crea una aplicación privada de HubSpot y copia su token de acceso

HubSpot ahora clasifica las aplicaciones privadas bajo aplicaciones heredadas, las cuales, según dicen, "todavía son compatibles con HubSpot, pero no tienen acceso a las funciones más recientes"; creas una en Desarrollo > Aplicaciones heredadas, y se requiere un superadministrador.

Otorga el content ámbito, que requiere la API de Blog Posts, y nombra la aplicación según el sitio que la utilizará para que quien herede la cuenta sepa para qué sirve el token

Asegúrate de saber qué abarca ese alcance antes de copiar el token. HubSpot no tiene un alcance de solo lectura para blogs: content "incluye sitios, páginas de destino, correo electrónico, blog y campañas", y el mismo alcance que permite a esta aplicación leer publicaciones permite a cualquiera que tenga el token editarlas o eliminarlas. No concedas nada más allá de eso y trata el token como una credencial de administrador.

El alcance seleccionado debería permitir que el sitio recupere el contenido publicado del blog sin otorgar acceso a otras partes de la cuenta.

Copia el token de acceso de la aplicación privada en un gestor de contraseñas.

Prefiero una aplicación privada dedicada para cada sitio que la consuma. Cuando una agencia entrega el sitio, revocar esa aplicación lo desconecta limpiamente sin tocar nada más en el portal. Ahora deberías tener un token de acceso y una aplicación privada con solo el content alcance.

2. Prepara la estructura de la aplicación Next.js con npm

Prepara el proyecto con npm y el App Router, utilizando una combinación de Next.js y Node.js compatible con Webflow Cloud. Mantén el proyecto configurado para npm durante toda la compilación para que la instalación de paquetes, tanto local como desplegada, utilice el mismo archivo de bloqueo y los mismos scripts.

Ejecuta el generador desde el directorio que contendrá el proyecto:

npx create-next-app@15 hubspot-teasers --typescript --app --no-tailwind --eslint --no-src-dir --import-alias "@/*" --use-npm
cd hubspot-teasers

Si el generador te pide opciones en lugar de usar un flag, elige npm, el App Router y ningún src directorio, porque las importaciones usan @/lib/hubspot.

Deja export const runtime = 'edge' fuera de cada ruta. Webflow Cloud despliega la aplicación en Cloudflare Workers, mientras que el objetivo de tiempo de ejecución de Next.js edge es un modo de compilación independiente que el adaptador OpenNext no admite. Deja basePath fuera de next.config también; Webflow Cloud inyecta la ruta de montaje en el momento de la compilación.

Crea un archivo .env.local para el desarrollo local con este contenido:

HUBSPOT_ACCESS_TOKEN=your-hubspot-private-app-token

Añade .env.local a .gitignore si el generador no lo hizo. Ahora tienes un proyecto que se ejecuta localmente con npm run dev y un token disponible para el código del servidor como process.env.HUBSPOT_ACCESS_TOKEN.

3. Escribe el módulo de obtención de HubSpot

Coloca la llamada a HubSpot en un módulo que importen tanto la página como el Route Handler. Mantenerlo en un solo lugar significa que el componente del servidor puede llamar al módulo directamente, lo que evita por completo la cuestión de la ruta base para la ruta renderizada en el servidor.

El módulo solicita las publicaciones publicadas y asigna cada una a un pequeño formato de avance. HubSpot no puede ordenar por fecha de publicación: sus campos de orden documentados son createdAt, name, updatedAt, createdBy y updatedBy, y cualquier valor no admitido vuelve al predeterminado, el más antiguo creado primero.

Por lo tanto, el módulo solicita las 20 publicaciones creadas más recientemente y ordena esa ventana por publishDate mismo. El único caso que puede pasar por alto es una publicación redactada hace mucho tiempo, con más de 20 publicaciones de antigüedad, y publicada hoy. Cualquier etiqueta HTML en postSummary se elimina antes de que el texto llegue a una página.

Guárdalo como :lib/hubspot.ts

const HUBSPOT_POSTS_URL = 'https://api.hubapi.com/cms/v3/blogs/posts';

// HubSpot cannot sort by publishDate, so fetch the 20 most recently created published
// posts (its default page size) and order that window by publish date here.
const WINDOW = 20;

export type Teaser = {
  title: string;
  summary: string;
  url: string;
  image: string | null;
  publishedAt: string;
};

type HubSpotPost = {
  name: string;
  postSummary?: string;
  url: string;
  featuredImage?: string;
  publishDate: string;
};

function stripHtml(html: string): string {
  return html.replace(/<[^>]*>/g, '').trim();
}

export async function getTeasers(limit = 3): Promise<Teaser[]> {
  const token = process.env.HUBSPOT_ACCESS_TOKEN;
  if (!token) {
    throw new Error('HUBSPOT_ACCESS_TOKEN is not set');
  }

  const params = new URLSearchParams({
    limit: String(WINDOW),
    state: 'PUBLISHED',
    sort: '-createdAt',
  });

  const res = await fetch(`${HUBSPOT_POSTS_URL}?${params.toString()}`, {
    headers: { Authorization: `Bearer ${token}` },
    cache: 'no-store',
  });

  if (!res.ok) {
    throw new Error(`HubSpot responded with ${res.status}`);
  }

  const data = (await res.json()) as { results?: HubSpotPost[] };

  return (data.results ?? [])
    .sort((a, b) => Date.parse(b.publishDate) - Date.parse(a.publishDate))
    .slice(0, limit)
    .map((post) => ({
    title: post.name,
    summary: stripHtml(post.postSummary ?? ''),
    url: post.url,
    image: post.featuredImage || null,
    publishedAt: post.publishDate,
  }));
}

La consulta solicita a la API de Blog Posts de HubSpot solo las publicaciones publicadas. En este código, cache: 'no-store' omite la caché de obtención de Next.js, por lo que cada solicitud lee en vivo desde HubSpot y una publicación recién publicada aparece en la siguiente carga de página.

Eso también significa que cada vista de página y cada carga de incrustación es una llamada a HubSpot. El límite de ráfaga de HubSpot en los planes Free y Starter es de 100 solicitudes por cada 10 segundos, y su límite diario se comparte entre todas las aplicaciones de la cuenta, por lo que un pico de tráfico aquí puede romper las otras integraciones de HubSpot del cliente durante el resto del día.

Antes de un lanzamiento con mucho tráfico, almacena los avances en la caché del almacén de clave-valor de Webflow Cloud durante al menos su TTL mínimo de 60 segundos. No intentes usar un encabezado Cache-Control; Webflow Cloud lo reemplaza con private, no-cache. Ahora tienes una función tipada que devuelve hasta tres avances o lanza un error con el código de estado de HubSpot.

4. Expón un Route Handler y renderiza los avances en el lado del servidor

Añade dos archivos: un Route Handler que devuelva los avances como JSON y una página que los renderice directamente. El Route Handler existe para las páginas creadas en el Designer que lo llamarán desde el navegador; la página existe para la ruta de montaje en sí y llama al módulo compartido directamente.

Ambos importan getTeasers.

Guarda el manejador como app/api/posts/route.ts:

import { NextResponse } from 'next/server';
import { getTeasers } from '@/lib/hubspot';

export async function GET() {
  try {
    const teasers = await getTeasers(3);
    return NextResponse.json({ teasers });
  } catch (err) {
    const message = err instanceof Error ? err.message : 'Unknown error';
    console.error(message);
    return NextResponse.json({ error: 'Could not load posts' }, { status: 502 });
  }
}

Devuelvo un 502 si HubSpot falla porque esta ruta de código falló durante una llamada ascendente a HubSpot. El manejador escribe los detalles de HubSpot en el lado del servidor a través de console.error, y el navegador solo recibe un error genérico.

Como no hay nada en caché, cada solicitud a /api/posts realiza una llamada a la API de HubSpot con tu token, por lo que el tráfico a esa ruta se convierte directamente en solicitudes a HubSpot.

Veredicto de seguridad: Este manejador de rutas de ejemplo es accesible públicamente y no implementa autenticación, limitación de tasa, cumplimiento de cuotas ni límites de gasto. Esto lo deja expuesto a tráfico automatizado que puede consumir la cuota de la API de HubSpot.

Antes de pasar a producción, añade un control de acceso y una limitación de tasa adecuados, y guarda la respuesta en caché como se describe en el paso 3. Mantén el token de HubSpot en HUBSPOT_ACCESS_TOKEN, nunca detrás de un prefijo NEXT_PUBLIC_.

Luego, reemplaza el app/page.tsx generado automáticamente con esto:

import { getTeasers, type Teaser } from '@/lib/hubspot';

export const dynamic = 'force-dynamic';

export default async function Page() {
  let teasers: Teaser[] = [];
  try {
    teasers = await getTeasers(3);
  } catch (err) {
    console.error(err instanceof Error ? err.message : 'Unknown error');
    teasers = [];
  }

  return (
    <section>
      <h2>Latest from the blog</h2>
      {teasers.length === 0 ? (
        <p>No posts yet.</p>
      ) : (
        <ul>
          {teasers.map((post) => (
            <li key={post.url}>
              {post.image && <img src={post.image} alt="" />}
              <h3>
                <a href={post.url}>{post.title}</a>
              </h3>
              <p>{post.summary}</p>
              <time dateTime={post.publishedAt}>
                {new Date(post.publishedAt).toLocaleDateString('en-US')}
              </time>
            </li>
          ))}
        </ul>
      )}
    </section>
  );
}

Ejecuta npm run dev y abre http://localhost:3000; deberías ver hasta tres publicaciones recientes, donde cada título enlaza a su respectiva entrada. Al acceder a http://localhost:3000/api/posts deberías obtener las mismas tres publicaciones en formato JSON bajo una clave teasers.

Un fallo de HubSpot en esta página escribe el error a través de console.error y muestra el mismo estado vacío que un blog sin publicaciones, así que investiga el error del lado del servidor antes de asumir que el blog está vacío.

5. Añade el token al entorno de Webflow Cloud y monta la aplicación

Almacena el token en el entorno de Webflow Cloud para que no quede en el repositorio conectado. Envía el proyecto al repositorio que vas a conectar, crea el proyecto de Webflow Cloud desde ese repositorio y establece su ruta de montaje en algo como /latest-posts.

En las variables del entorno, añade HUBSPOT_ACCESS_TOKEN y márcala como secreta. Si más adelante cambias el token en HubSpot, pega el nuevo valor en esta misma variable. Las variables de entorno, tanto secretas como públicas, están disponibles para el proceso de compilación y para la aplicación desplegada en tiempo de ejecución, y los valores secretos se ocultan en los registros de compilación. Por lo tanto, la variable no queda expuesta en el repositorio.

Confirma la configuración del secreto y la ruta de montaje en la configuración del entorno.

Despliega. Una vez finalizado el despliegue, abre /latest-posts en el dominio donde se publica tu sitio (un dominio personalizado requiere un plan Premium o superior), y deberías ver los mismos tres avances que viste localmente; con el prefijo de la ruta de montaje, /latest-posts/api/posts debería devolver el JSON.

6. Inserta los avances en una página creada en el Designer

Inserta los avances llamando al manejador de rutas montado desde código personalizado en la página publicada del Designer. La aplicación y la página del Designer comparten origen cuando la aplicación se monta en una ruta del mismo sitio, por lo que la solicitud no debería necesitar una configuración de intercambio de recursos de origen cruzado (CORS).

Webflow Cloud inyecta la ruta de montaje en la aplicación durante la compilación, mientras que una solicitud fetch del navegador conserva la URL escrita en el script. La guía de Webflow Cloud sobre cómo usar tu propia aplicación lo dice claramente: "Las llamadas fetch del lado del cliente deben incluir manualmente la ruta base". En un elemento insertado (embed) que vive en el Designer, escribe tú mismo la ruta de montaje en la URL.

Añade esto en un elemento Code Embed donde deberían aparecer los avances. Publicar código personalizado requiere un plan de sitio de pago o un Workspace Core, Growth, Agency o Freelancer, por lo que un sitio Starter gratuito puede ejecutar la aplicación pero no este elemento insertado:

<div id="hubspot-teasers"></div>
<script>
  (async () => {
    const mountPath = '/latest-posts';
    const container = document.getElementById('hubspot-teasers');
    const res = await fetch(`${mountPath}/api/posts`);
    if (!res.ok) return;
    const { teasers } = await res.json();
    teasers.forEach((t) => {
      const a = document.createElement('a');
      a.className = 'teaser';
      a.href = t.url;

      const strong = document.createElement('strong');
      strong.textContent = t.title;

      const p = document.createElement('p');
      p.textContent = t.summary;

      a.append(strong, p);
      container.append(a);
    });
  })();
</script>

El elemento insertado construye los elementos y establece textContent, por lo que ningún campo de HubSpot se analiza como HTML. Si un componente del lado del cliente dentro de la propia aplicación Next.js necesita el manejador, lee la ruta de montaje desde una variable NEXT_PUBLIC_BASE_PATH.

Usa ese prefijo solo para la ruta de montaje no secreta. Publica el sitio de Webflow, carga la página y el elemento insertado debería llenarse con los mismos tres avances que muestra la aplicación montada. El script se ejecuta en el sitio publicado, por lo que el lienzo del Designer mostrará el contenedor vacío.

¿Qué causa que los avances de HubSpot fallen en Webflow Cloud?

Los teasers de HubSpot suelen fallar debido a una directiva de tiempo de ejecución no compatible, una credencial de despliegue faltante, una solicitud de navegador sin prefijo o una discrepancia en el gestor de paquetes entre el repositorio y Webflow Cloud.

Identifica el síntoma visible y aplica la solución correspondiente antes de modificar el módulo de obtención (fetch).

La compilación de Webflow Cloud falla o las rutas de la API devuelven errores tras el despliegue

Causa: El proyecto suele contener en una o más rutas. Webflow Cloud se despliega a través de OpenNext en Cloudflare Workers, pero el objetivo de tiempo de ejecución edge de Next.js es un modo de compilación independiente que el adaptador no admite.export const runtime = 'edge'

Es posible que un servidor de desarrollo local no muestre la misma incompatibilidad de despliegue, razón por la cual el fallo puede aparecer por primera vez durante la compilación de Webflow Cloud o después del despliegue.

Solución: Busca en todos los archivos del proyecto y elimina cada aparición. Mantén fuera de porque Webflow Cloud inyecta la ruta de montaje durante la compilación. Vuelve a desplegar y solicita . Una respuesta exitosa debería contener una clave en lugar de un error de compilación de la plataforma o un fallo en la ruta.export const runtime = 'edge'basePathnext.config/latest-posts/api/poststeasers

La página montada muestra "No posts yet." y la ruta de la API devuelve un error 502

Causa: La diferencia entre una aplicación local que funciona y un error 502 tras el despliegue apunta a la fuente de las credenciales, que cambia entre entornos. Localmente, el valor proviene de , que se excluye correctamente del repositorio; en Webflow Cloud, proviene de las variables de entorno. Un error tipográfico en el nombre de la variable, espacios en blanco al final del token pegado, un token rotado o una aplicación privada recreada pueden producir el mismo resultado visible..env.local

Solución: Revisa el entorno desplegado y pega el token directamente desde la página de la aplicación privada de HubSpot. Confirma que la variable se llame y que la aplicación privada aún tenga el alcance . El gestor de rutas envía detalles a la : "HUBSPOT_ACCESS_TOKEN is not set" significa que falta la variable, mientras que "HubSpot responded with" seguido de un código de estado indica que la solicitud llegó a HubSpot pero no tuvo éxito.HUBSPOT_ACCESS_TOKENcontentconsole.error

El elemento incrustado (embed) del Diseñador permanece vacío porque su solicitud a falla/api/posts

Causa: Una solicitud a se enruta fuera de la aplicación montada porque el navegador utiliza la URL literal en el elemento incrustado. Webflow Cloud inyecta la ruta de montaje para la compilación de la aplicación, pero no puede reescribir una URL del lado del cliente almacenada en el código personalizado del Diseñador. El mismo error de enrutamiento puede aparecer dentro de la aplicación Next.js cuando un componente del lado del cliente obtiene una URL relativa sin el prefijo de la ruta de montaje pública./api/posts

Solución: Cambia la solicitud del Diseñador a o constrúyela a partir de la constante que se muestra en el elemento incrustado. Dentro de la aplicación, utiliza para la ruta de montaje no secreta, de modo que un cambio de ruta posterior solo requiera actualizar una variable./latest-posts/api/postsmountPathNEXT_PUBLIC_BASE_PATH

Mantén libre de una configurada manualmente. Tras publicar, la solicitud del navegador debería llegar al gestor montado y completar el contenedor vacío.next.configbasePath

La compilación de Webflow Cloud falla aunque npm funcione localmente

Causa: Un archivo o entra en conflicto con la configuración de npm de este proyecto, mientras que los scripts de que llaman a o dependen de herramientas que el despliegue no está configurado para usar. Una compilación local puede funcionar si tu máquina tiene instalados esos gestores de paquetes, ocultando la discrepancia hasta que Webflow Cloud instala las dependencias desde el repositorio conectado.pnpm-lock.yamlyarn.lockpackage.jsonpnpmyarn

Solución: Migra el proyecto completamente a npm. Elimina el archivo de bloqueo de pnpm o yarn y ejecuta para generar . Reemplaza cualquier llamada a o en los scripts de por sus equivalentes en . Confirma el nuevo archivo de bloqueo y los scripts actualizados, luego vuelve a desplegar. El repositorio debe contener un único archivo de bloqueo de gestor de paquetes y Webflow Cloud debe ejecutar los mismos comandos de npm que funcionan localmente.npm installpackage-lock.jsonpnpmyarnpackage.jsonnpm run

Qué puedes construir a continuación con HubSpot y Webflow

Una vez que tus teasers se actualicen solos, puedes extender el mismo límite del lado del servidor a un índice de blog completo con un más grande, mientras que un bloque de publicaciones relacionadas requeriría un filtrado que el módulo aún no realiza.limit

Para la dirección opuesta, enviar clientes potenciales de formularios de Webflow a HubSpot, consulta . Explora la para conocer más formas de conectar HubSpot y Webflow.

Preguntas frecuentes

¿Cómo muestro más de tres publicaciones?

Cambia el pasado a tanto en como en ; las dos llamadas son independientes, así que actualízalas juntas. Hasta 20 funciona tal como está escrito, porque esa es la ventana que obtiene el módulo. Más allá de 20, aumenta también . Después de aumentar la cantidad, prueba la página montada y el elemento incrustado del Diseñador en anchos estrechos, con títulos largos e imágenes faltantes, ya que una respuesta más grande puede exponer problemas de diseño que tres tarjetas no revelaban.3getTeasersapp/page.tsxapp/api/posts/route.tsWINDOW

¿Puedo construir esto en Astro en lugar de Next.js?

Sí. La solicitud a HubSpot y el puerto del límite de tokens del lado del servidor no cambian, pero la lectura del token sí: Webflow documenta locals.runtime.env para rutas de Astro, así que lee HUBSPOT_ACCESS_TOKEN desde allí en lugar de process.env. Sustituye el Route Handler por un endpoint de servidor de Astro y reemplaza page.tsx por una página .astro renderizada en el servidor. Mantén la ruta de montaje fuera de la configuración del framework e inclúyela manualmente en las solicitudes del navegador.

¿Puedo proteger el Route Handler con middleware?

Sí. Puedes añadir middleware.ts para verificar las solicitudes antes de que lleguen al Route Handler, y se ejecuta como middleware de Edge en el entorno de ejecución de Workers. Mantén el nombre de archivo del middleware en lugar de renombrarlo a proxy, porque esa opción se ejecuta en el entorno de Node y no puede optar por Edge para el despliegue en Webflow Cloud.

¿Puedo usar el mismo embed en varias páginas del Designer?

Sí, en un plan que permita publicar código personalizado: puedes añadir el mismo embed a cada página del Designer que necesite avances. Mantén mountPath configurado como /latest-posts en cada copia, ya que identifica el montaje de la aplicación, no la página actual. Actualiza todas las copias si más adelante cambias la ruta de montaje de la aplicación. Usa una ubicación de código compartida a nivel de sitio cuando todas las páginas necesiten el mismo marcado.


Última actualización
October 2, 2026
Categoría

Artículos relacionados


verifone logomonday.com logospotify logoted logogreenhouse logoclear logocheckout.com logoreddit logothe new york times logoideo logoupwork logodiscord logo
verifone logomonday.com logospotify logoted logogreenhouse logoclear logocheckout.com logoreddit logothe new york times logoideo logoupwork logodiscord logo

Empieza gratis

Prueba Webflow todo el tiempo que quieras con nuestro plan Starter gratuito. Compra un plan de sitio de pago para publicar, alojar y desbloquear funciones adicionales.

Empieza, es gratis
Ver demostración

Prueba Webflow todo el tiempo que quieras con nuestro plan Starter gratuito. Compra un plan de sitio de pago para publicar, alojar y desbloquear funciones adicionales.