Cómo crear un asistente de contenido con Gemini que viva dentro de tu CMS de Webflow

Cómo crear un asistente de contenido con Gemini integrado en tu CMS de Webflow

Aprende a crear un asistente de contenido con Gemini en Webflow Cloud que transmite borradores y devuelve JSON listo para el CMS.

Cómo crear un asistente de contenido con Gemini integrado en tu CMS de Webflow

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

Un asistente de contenido que se integra en tu CMS y te devuelve campos listos para pegar sin necesidad de reformatear cambia por completo la forma en que los editores trabajan en Webflow.

Los editores de contenido que trabajan en el CMS de Webflow pierden una cantidad sorprendente de tiempo en los mismos puntos de fricción. Se quedan mirando un campo en blanco, reformatean un borrador para adaptarlo a los campos que espera su colección o saltan de una ventana de chat de IA al panel de control de Webflow para copiar y pegar contenido.

Un asistente de contenido con Gemini integrado en Webflow Cloud elimina los tres problemas. Vive en el mismo entorno que tu sitio, entiende la estructura de tu colección del CMS y puede devolver tanto un borrador en streaming para escritura libre como un objeto JSON estructurado que se asigna directamente a los campos de tu CMS de Webflow.

Cuando Gemini genera un objeto JSON ya formateado para el CMS de Webflow, el ciclo de copiar, pegar y reformatear desaparece por completo.

En esta guía, crearemos ese asistente en Webflow Cloud con Next.js y la API de Gemini, y luego añadiremos dos modos: un modo de borrador en streaming para escritura libre y un modo CMS que devuelve campos que puedes pegar directamente en tu colección.

¿Qué necesitas para crear un asistente de contenido con Gemini en Webflow Cloud?

Necesitas un proyecto de Next.js en Webflow Cloud y una clave de API de Gemini de Google AI Studio. El @google/genai SDK se comunica con Gemini a través de fetch, por lo que se ejecuta en el entorno de ejecución Workers de Webflow Cloud sin dependencias específicas de Node.js. No añadas export const runtime = 'edge' a tus rutas: el adaptador OpenNext Cloudflare que utiliza Webflow Cloud no lo admite.

Aquí tienes la lista de requisitos:

  • Un proyecto de Webflow Cloud ejecutando una aplicación Next.js, ya sea desplegada o en desarrollo local
  • Una clave de API de Gemini (nivel gratuito disponible en aistudio.google.com/apikey)
  • Node.js 22.13.0 o superior en local, el requisito mínimo establecido por Webflow CLI 2.x; el @google/genai SDK en sí solo requiere Node 20
  • Conocimientos básicos de los nombres de los campos de las colecciones del CMS de Webflow (los referenciarás en el prompt del sistema)

Sin proxies de IA de terceros, plataformas de funciones serverless ni hosting independiente. Todo se ejecuta en una única aplicación de Webflow Cloud.

5 pasos para crear un asistente de contenido con Gemini para Webflow

La arquitectura se divide en dos partes:

  • Un Route Handler de streaming que llama a Gemini y devuelve la salida como un flujo de texto
  • Un componente de cliente que envía el prompt del editor y renderiza la respuesta palabra por palabra

Un segundo endpoint, sin streaming, gestiona el "modo CMS": genera un objeto JSON que se asigna directamente a los campos del CMS de Webflow.

Utilizo dos modos en cada proyecto. El modo de borrador en streaming para una exploración abierta y el modo JSON para obtener una salida estructurada lista para el CMS. A los redactores les encanta el streaming porque se siente como algo en vivo. A mí me encanta el modo JSON porque elimina el paso de reformateo del flujo de trabajo de publicación.

1. Obtén una clave de API de Gemini e instala el SDK

Inicia sesión o regístrate en Google AI Studio. Haz clic en Get API key > Create API key. Copia la clave y guárdala en un lugar seguro.

Instala el SDK de Google Gen AI en tu proyecto de Webflow Cloud:

npm install @google/genai

Añade tu clave de API a .env.local y al panel de variables de entorno de Webflow Cloud en Settings > Environment Variables:

GEMINI_API_KEY=your_gemini_api_key_here

No le pongas el prefijo NEXT_PUBLIC_. Cualquier variable con el prefijo NEXT_PUBLIC_ se incluye en el paquete JavaScript del navegador. Una clave de API de Gemini pública permite que cualquiera ejecute solicitudes de generación que se cargarán a tu cuenta.

2. Crea el gestor de rutas de streaming de Gemini en Webflow Cloud

El endpoint de streaming recibe un prompt del editor, llama a Gemini con un prompt del sistema que define el tono y el formato de salida, y luego transmite la respuesta como texto plano. El bucle for await en el stream de Gemini envía fragmentos a un ReadableStream que Next.js envía directamente al navegador.

Aquí tienes el fragmento:

// app/api/assist/stream/route.ts
import { GoogleGenAI } from '@google/genai'
import { type NextRequest } from 'next/server'

const SYSTEM_PROMPT = `You are a content editor for a Webflow site.
Your writing is clear, specific, and aimed at practitioners.
Avoid filler phrases, excessive hedging, and generic transitions.
Match the requested tone. Output plain prose without markdown headers
unless the user explicitly asks for structured content.`

export async function POST(request: NextRequest) {
  const { topic, tone } = await request.json() as {
    topic: string
    tone: 'professional' | 'conversational' | 'technical'
  }

  const prompt = `Write a first draft about: ${topic}\nTone: ${tone}`

  const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY! })

  const stream = new ReadableStream({
    async start(controller) {
      try {
        const responseStream = await ai.models.generateContentStream({
          model: 'gemini-3.5-flash',
          contents: prompt,
          config: {
            systemInstruction: SYSTEM_PROMPT,
            maxOutputTokens: 1024,
          },
        })

        for await (const chunk of responseStream) {
          if (chunk.text) {
            controller.enqueue(new TextEncoder().encode(chunk.text))
          }
        }
      } catch (err) {
        controller.error(err)
        return
      }
      controller.close()
    },
  })

  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  })
}

Con este gestor, una solicitud POST a /api/assist/stream devuelve la salida de Gemini como un stream de texto en vivo en lugar de un bloque único. El navegador lo lee fragmento a fragmento, lo que produce el efecto de máquina de escribir en la interfaz que construirás en el paso 4.

El manejo de errores es importante aquí. Llamar a controller.error() cuando Gemini falla permite mostrar el error en el navegador, en lugar de cerrar el stream silenciosamente, lo cual sería indistinguible de una respuesta vacía exitosa.

3. Crea el gestor de rutas en modo CMS de Gemini en Webflow Cloud

El endpoint en modo CMS utiliza la función de salida estructurada de Gemini (responseMimeType: 'application/json' con un responseSchema) para devolver un objeto JSON que se asigna exactamente a tus campos del CMS de Webflow. El editor obtiene un resultado que puede pegar directamente, sin necesidad de reformatear.

Aquí tienes el gestor de rutas en modo CMS que ajusta la salida al esquema de tu colección:

// app/api/assist/cms/route.ts
import { GoogleGenAI } from '@google/genai'
import { NextResponse, type NextRequest } from 'next/server'

// Adjust these field names to match your Webflow CMS collection.
const CMS_SCHEMA = {
  type: 'object',
  properties: {
    name: { type: 'string', description: 'CMS item name, max 80 characters' },
    slug: { type: 'string', description: 'URL slug, lowercase, hyphenated' },
    excerpt: { type: 'string', description: 'Short summary, max 160 characters' },
    body: { type: 'string', description: 'Full article body in plain text' },
    tags: {
      type: 'array',
      items: { type: 'string' },
      description: 'Up to 5 relevant tags',
    },
  },
  required: ['name', 'slug', 'excerpt', 'body'],
}

export async function POST(request: NextRequest) {
  const { topic, tone } = await request.json() as {
    topic: string
    tone: string
  }

  const prompt = `Create Webflow CMS content about: ${topic}\nTone: ${tone}`

  const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY! })

  const response = await ai.models.generateContent({
    model: 'gemini-3.5-flash',
    contents: prompt,
    config: {
      systemInstruction: `You are a Webflow content editor.
        Output only valid JSON matching the provided schema.
        The body field should be 300-500 words of plain text.`,
      responseMimeType: 'application/json',
      responseSchema: CMS_SCHEMA,
      maxOutputTokens: 2048,
      temperature: 0.5,
    },
  })

  const json = JSON.parse(response.text ?? '{}')
  return NextResponse.json(json)
}

Una nota sobre responseSchema: la referencia de la API de Google ahora lo marca como obsoleto, aunque sigue estando totalmente documentado, no tiene fecha de eliminación anunciada y debe combinarse con un responseMimeType compatible. Considéralo algo para revisar más adelante, no algo que debas reescribir hoy.

Según mi experiencia, el prompt del sistema hace más por la calidad de la salida que cualquier otra cosa en este desarrollo. Paso más tiempo ajustando la instrucción del sistema (ajustando objetivos de conteo de palabras, añadiendo descripciones de campos, especificando qué significa "texto plano" para una configuración de CMS determinada) que escribiendo el código de la aplicación.

4. Crea la interfaz del asistente de contenido de Gemini

El componente de cliente gestiona el estado del formulario y el lector de streaming. Cuando el editor envía un prompt, abre un ReadableStream de la respuesta fetch y añade cada fragmento decodificado a una variable de estado, produciendo el efecto de máquina de escribir.

Aquí tienes el componente de cliente que gestiona el estado del formulario y el lector de streaming:

// app/content-assistant/ContentAssistant.tsx
'use client'

import { useState } from 'react'

type Mode = 'draft' | 'cms'
type Tone = 'professional' | 'conversational' | 'technical'

type CmsOutput = {
  name: string
  slug: string
  excerpt: string
  body: string
  tags?: string[]
}

export default function ContentAssistant() {
  const [topic, setTopic] = useState('')
  const [tone, setTone] = useState<Tone>('professional')
  const [mode, setMode] = useState<Mode>('draft')
  const [output, setOutput] = useState('')
  const [cmsOutput, setCmsOutput] = useState<CmsOutput | null>(null)
  const [loading, setLoading] = useState(false)

  async function generate() {
    if (!topic.trim() || loading) return
    setLoading(true)
    setOutput('')
    setCmsOutput(null)

    try {
      if (mode === 'draft') {
        const res = await fetch('/api/assist/stream', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ topic, tone }),
        })

        if (!res.ok) throw new Error('Request failed')

        const reader = res.body!.getReader()
        const decoder = new TextDecoder()

        while (true) {
          const { done, value } = await reader.read()
          if (done) break
          setOutput((prev) => prev + decoder.decode(value, { stream: true }))
        }
      } else {
        const res = await fetch('/api/assist/cms', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ topic, tone }),
        })
        const data = await res.json() as CmsOutput
        setCmsOutput(data)
      }
    } finally {
      setLoading(false)
    }
  }

  return (
    <div className="content-assistant">
      <h1>Gemini Content Assistant</h1>

      <div className="assistant-controls">
        <div className="mode-toggle">
          <button
            className={mode === 'draft' ? 'active' : ''}
            onClick={() => setMode('draft')}
          >
            Draft mode
          </button>
          <button
            className={mode === 'cms' ? 'active' : ''}
            onClick={() => setMode('cms')}
          >
            CMS mode
          </button>
        </div>

        <textarea
          value={topic}
          onChange={(e) => setTopic(e.target.value)}
          placeholder="Describe what you want to write about..."
          rows={3}
          className="assistant-input"
        />

        <select
          value={tone}
          onChange={(e) => setTone(e.target.value as Tone)}
          className="assistant-tone"
        >
          <option value="professional">Professional</option>
          <option value="conversational">Conversational</option>
          <option value="technical">Technical</option>
        </select>

        <button
          onClick={generate}
          disabled={loading || !topic.trim()}
          className="assistant-submit"
        >
          {loading ? 'Generating...' : 'Generate'}
        </button>
      </div>

      {mode === 'draft' && output && (
        <div className="assistant-output">
          <pre>{output}</pre>
          <button onClick={() => navigator.clipboard.writeText(output)}>
            Copy to clipboard
          </button>
        </div>
      )}

      {mode === 'cms' && cmsOutput && (
        <div className="assistant-cms-output">
          <div className="cms-field">
            <label>Name</label>
            <p>{cmsOutput.name}</p>
          </div>
          <div className="cms-field">
            <label>Slug</label>
            <code>{cmsOutput.slug}</code>
          </div>
          <div className="cms-field">
            <label>Excerpt</label>
            <p>{cmsOutput.excerpt}</p>
          </div>
          {cmsOutput.tags && (
            <div className="cms-field">
              <label>Tags</label>
              <p>{cmsOutput.tags.join(', ')}</p>
            </div>
          )}
          <div className="cms-field">
            <label>Body</label>
            <pre>{cmsOutput.body}</pre>
          </div>
          <button
            onClick={() => navigator.clipboard.writeText(JSON.stringify(cmsOutput, null, 2))}
          >
            Copy as JSON
          </button>
        </div>
      )}
    </div>
  )
}

Este componente controla ambos modos desde un mismo formulario. En el modo borrador, lee el stream de respuesta y añade cada fragmento al estado, por lo que el texto aparece a medida que se genera. En el modo CMS, espera a que llegue el objeto JSON completo y luego renderiza cada campo con su propio control de copia. Ambas rutas comparten las mismas entradas de tema y tono, por lo que cambiar de modo nunca obliga al editor a volver a introducir nada.

5. Añade el asistente de contenido de Gemini a una página de Webflow Cloud

Crea la página que aloja al asistente. Dado que es un componente de cliente, la página en sí es un contenedor de componente de servidor:ContentAssistant

// app/content-assistant/page.tsx
import ContentAssistant from './ContentAssistant'

export default function ContentAssistantPage() {
  return (
    <main className="assistant-page">
      <ContentAssistant />
    </main>
  )
}

El asistente ya está activo en en tu aplicación de Webflow Cloud. Si la aplicación se despliega como parte de un sitio de Webflow, móntala en la ruta que configures en Configuración del sitio > Webflow Cloud. El acceso puede restringirse con cualquier middleware de autenticación; consulta la guía de Supabase Auth para limitar el asistente a los miembros del equipo que hayan iniciado sesión./content-assistant

¿Qué puede hacer que el asistente de contenido de Gemini falle en Webflow?

La mayoría de los fallos con el asistente de contenido de Gemini se deben a tres causas: un límite de tokens de salida demasiado bajo, JSON mal formado en modo CMS y una clave de API que funciona en local pero no en producción. Cada uno aparece en un punto predecible y tiene una solución rápida una vez que conoces el origen.

Aquí tienes cada patrón de fallo.

La respuesta en streaming está vacía o se detiene a mitad de frase

La causa más común es que el límite de sea demasiado bajo para el contenido solicitado. El ejemplo anterior lo establece en 1024 tokens, lo cual es suficiente para un borrador de 300-400 palabras.maxOutputTokens

Para contenido más largo, aumenta (Gemini 3.5 Flash admite hasta ). Comprueba también que el bloque esté presente; sin él, un error de la API de Gemini deja el flujo abierto y la interfaz se bloquea.maxOutputTokensfinally { controller.close() }

La salida JSON del CMS tiene texto adicional o formato markdown alrededor del JSON

Esto sucede cuando se establece , pero el modelo añade una explicación. Pasa siempre junto con en la configuración; sin el esquema, el modelo puede envolver el JSON en bloques de código markdown.responseMimeTyperesponseMimeType: 'application/json'responseSchema

Si sigues viendo texto adicional, añade "Output only raw JSON. No explanation, no code fences." a la instrucción del sistema.

La clave de API de Gemini es rechazada en producción

Comprueba que esté configurada en las variables de entorno de Webflow Cloud en Configuración > Variables de entorno, y no solo en . Las variables de entorno configuradas localmente no se trasladan a producción.GEMINI_API_KEY.env.local

Verifica también que la clave no haya alcanzado el límite de tasa del nivel gratuito; el nivel gratuito de Gemini tiene límites de generación por minuto que pueden superarse rápidamente durante las pruebas.

Amplía tu asistente de contenido de Gemini para flujos de trabajo de Webflow CMS

El asistente de esta guía cubre los dos patrones que utilizo en todos mis proyectos: borradores en streaming y salida estructurada para CMS. Ambos se pueden ampliar fácilmente a partir de aquí.

Para revisiones de múltiples turnos, cambia la llamada a por y mantén el objeto de chat en una referencia de React entre renderizados. Así, el editor podrá pedirle a Gemini que reescriba un párrafo específico, cambie el tono o acorte el fragmento sin perder el contexto original.generateContentai.chats.create()

Explora Webflow + Gemini para conocer las opciones de conexión, las capacidades admitidas y las notas de configuración que sustentan la construcción de esta guía.

Para el despliegue en Webflow Cloud y la configuración del entorno, consulta la documentación de Webflow Cloud.

Preguntas frecuentes

¿Qué modelo de Gemini debería usar?

gemini-3.5-flashes la opción predeterminada ideal para la mayoría de los asistentes de contenido. Es lo suficientemente rápido para streaming en tiempo real, maneja resultados extensos con fluidez y admite la salida JSON estructurada mediante el parámetro . Para contenido que requiera un razonamiento más profundo o una ventana de contexto mayor, sube al nivel Pro de Google. Gemini 3.1 Pro () es el modelo de clase Pro disponible a través de la API actualmente, mientras que Gemini 3.5 Pro fue anunciado en Google I/O 2026 pero aún no es accesible vía API. Pro sacrifica velocidad por capacidad de razonamiento, así que úsalo solo cuando Flash no sea suficiente.responseMimeTypegemini-3.1-pro-preview

¿El SDK @google/genai funciona en Webflow Cloud?

Sí. El SDK utiliza la API Fetch para solicitudes HTTP, la cual está disponible en el entorno de ejecución de Cloudflare Workers sobre el que corre Webflow Cloud. No añadas a la ruta: el entorno de ejecución edge de Next.js no es compatible con el adaptador OpenNext de Cloudflare, y mantener esa directiva provocará un error en la compilación.@google/genaiexport const runtime = 'edge'

¿Puedo conectar el asistente directamente al CMS de Webflow para publicar contenido?

No directamente desde el Route Handler, pero el camino es sencillo. Una vez que el endpoint del modo CMS devuelva un objeto JSON, realiza una solicitud a la API de datos de Webflow en usando un token de sitio con alcance . El JSON de Gemini se asigna al objeto en el cuerpo de la solicitud de la API de Webflow.POSThttps://api.webflow.com/v2/collections/{collection_id}/itemsCMS:writefieldData

¿Qué incluye el nivel gratuito de Gemini?

El nivel gratuito de la API de Gemini incluye acceso con límites de tasa a sin necesidad de facturación. Para un asistente de contenido utilizado por un equipo pequeño, el nivel gratuito suele ser suficiente para pruebas y un uso ligero en producción. Los casos de uso de alto volumen requieren un plan de pago. Los límites de tasa varían según el nivel de uso y se muestran por proyecto en AI Studio; consulta cómo se asignan los límites y los precios por token para ver las cifras actuales.gemini-3.5-flash

¿Cómo evito que los editores envíen prompts arbitrarios a Gemini?

Dos enfoques funcionan muy bien juntos: valida y limpia el campo en el Route Handler antes de que llegue a Gemini (establece un límite de caracteres, elimina etiquetas HTML) y define instrucciones del sistema para delimitar qué debe y qué no debe hacer el modelo. Para equipos donde el alcance del contenido está estrictamente controlado, añadir un menú desplegable con tipos de contenido predefinidos (artículo de blog, descripción de producto, anuncio) sustituye al campo de texto libre y mantiene la generación dentro de los límites esperados.topic


Última actualización
August 8, 2026
Categoría

Artículos relacionados

La forma correcta de añadir el chat en vivo de Crisp a una aplicación de Webflow Cloud
La forma correcta de añadir el chat en vivo de Crisp a una aplicación de Webflow Cloud

La forma correcta de añadir el chat en vivo de Crisp a una aplicación de Webflow Cloud

La forma correcta de añadir el chat en vivo de Crisp a una aplicación de Webflow Cloud

Guías
Por
Ismail Ajagbe
,
,
Leer artículo
Cómo añadir protección contra spam reCAPTCHA a los formularios de Webflow y bloquear bots automatizados
Cómo añadir protección contra spam reCAPTCHA a los formularios de Webflow y bloquear bots automatizados

Cómo añadir protección contra spam reCAPTCHA a los formularios de Webflow y bloquear bots automatizados

Cómo añadir protección contra spam reCAPTCHA a los formularios de Webflow y bloquear bots automatizados

Desarrollo
Por
Colin Lateano
,
,
Leer artículo
Cómo crear una aplicación serverless con Neon Postgres y Webflow Cloud
Cómo crear una aplicación serverless con Neon Postgres y Webflow Cloud

Cómo crear una aplicación serverless con Neon Postgres y Webflow Cloud

Cómo crear una aplicación serverless con Neon Postgres y Webflow Cloud

Desarrollo
Por
Colin Lateano
,
,
Leer artículo
Cómo añadir una ventana emergente de Calendly a Webflow y mantener a tus visitantes en el sitio
Cómo añadir una ventana emergente de Calendly a Webflow y mantener a tus visitantes en el sitio

Cómo añadir una ventana emergente de Calendly a Webflow y mantener a tus visitantes en el sitio

Cómo añadir una ventana emergente de Calendly a Webflow y mantener a tus visitantes en el sitio

Desarrollo
Por
Colin Lateano
,
,
Leer artículo

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.