Ein Content-Assistent, der neben Ihrem CMS sitzt und Felder liefert, die Sie ohne Umformatierung einfügen können, verändert die Arbeitsweise von Redakteur:innen in Webflow.
Content-Redakteur:innen, die im Webflow CMS arbeiten, verlieren erstaunlich viel Zeit an dieselben Reibungspunkte. Sie starren auf ein leeres Feld, formatieren einen Entwurf in die von ihrer Collection erwarteten Felder um, oder wechseln zwischen einem KI-Chatfenster und dem Webflow-Dashboard, um Content zu kopieren und einzufügen.
Ein von Gemini angetriebener Content-Assistent, gebaut auf Webflow Cloud, beseitigt alle drei Punkte. Er lebt in derselben Umgebung wie Ihre Website, versteht die Struktur Ihrer CMS-Collection und kann entweder einen gestreamten Entwurf für offenes Schreiben oder ein strukturiertes JSON-Objekt zurückgeben, das direkt auf Ihre Webflow-CMS-Felder abbildet.
Wenn Gemini ein JSON-Objekt ausgibt, das bereits für das Webflow CMS formatiert ist, verschwindet die Kopieren-Einfügen-Umformatieren-Schleife vollständig.
In diesem Leitfaden bauen wir diesen Assistenten auf Webflow Cloud mit Next.js und der Gemini API und fügen dann zwei Modi hinzu: einen Streaming-Entwurfsmodus für offenes Schreiben und einen CMS-Modus, der Felder zurückgibt, die Sie direkt in Ihre Collection einfügen können.
Was brauchen Sie, um einen Gemini-Content-Assistenten in Webflow Cloud zu bauen?
Sie brauchen ein Webflow-Cloud-Next.js-Projekt und einen Gemini-API-Key von Google AI Studio. Das @google/genai-SDK kommuniziert über fetch mit Gemini und läuft daher auf Webflow Clouds Workers-Runtime ohne Node.js-spezifische Abhängigkeiten. Fügen Sie Ihren Routen kein export const runtime = 'edge' hinzu: Der OpenNext-Cloudflare-Adapter, den Webflow Cloud verwendet, unterstützt das nicht.
Hier ist die Liste der Voraussetzungen:
- Ein Webflow-Cloud-Projekt mit einer laufenden Next.js-App, deployed oder in lokaler Entwicklung
- Ein Gemini-API-Key (kostenlose Stufe verfügbar unter aistudio.google.com/apikey)
- Node.js 22.13.0 oder höher lokal, die Untergrenze, die von Webflow CLI 2.x vorgegeben wird; das
@google/genai-SDK selbst benötigt nur Node 20 - Grundlegende Vertrautheit mit den Feldnamen Ihrer Webflow-CMS-Collection (Sie referenzieren sie im System-Prompt)
Kein Drittanbieter-KI-Proxy, keine Serverless-Function-Plattform, kein separates Hosting. Alles läuft in einer einzigen Webflow-Cloud-App.
5 Schritte zum Bau eines Gemini-Content-Assistenten für Webflow
Die Architektur teilt sich in zwei Teile:
- Ein Streaming-Route-Handler, der Gemini aufruft und die Ausgabe als Text-Stream zurückgibt
- Eine Client Component, die den Prompt der Redakteurin sendet und die Antwort Wort für Wort rendert
Ein zweiter, nicht streamender Endpoint übernimmt den „CMS-Modus": Er gibt ein JSON-Objekt aus, das direkt auf die Webflow-CMS-Felder abbildet.
Ich nutze bei jedem Projekt zwei Modi. Streaming-Entwurfsmodus für offene Exploration, JSON-Modus für strukturierte, CMS-fertige Ausgabe. Autor:innen lieben Streaming, weil es sich live anfühlt. Ich liebe den JSON-Modus, weil er den Umformatierungsschritt aus dem Publishing-Workflow entfernt.
1. Holen Sie sich einen Gemini-API-Key und installieren Sie das SDK
Melden Sie sich bei Google AI Studio an oder registrieren Sie sich. Klicken Sie auf Get API key > Create API key. Kopieren Sie den Key und bewahren Sie ihn sicher auf.
Installieren Sie das Google Gen AI SDK in Ihrem Webflow-Cloud-Projekt:
npm install @google/genai
Fügen Sie Ihren API-Key zu .env.local und zum Environment-Dashboard von Webflow Cloud unter Settings > Environment Variables hinzu:
GEMINI_API_KEY=your_gemini_api_key_here
Versehen Sie diesen nicht mit dem Präfix NEXT_PUBLIC_. Jede Variable mit dem Präfix NEXT_PUBLIC_ wird in das JavaScript-Bundle des Browsers aufgenommen. Ein öffentlicher Gemini-API-Key erlaubt es jedem, Generierungsanfragen auszuführen, die Ihrem Account in Rechnung gestellt werden.
2. Bauen Sie den Gemini-Streaming-Route-Handler in Webflow Cloud
Der Streaming-Endpoint empfängt einen Prompt von der Redakteurin, ruft Gemini mit einem System-Prompt auf, der Tonalität und Ausgabeformat festlegt, und streamt die Antwort dann als Plain Text zurück. Die for await-Schleife auf dem Gemini-Stream speist Chunks in einen ReadableStream ein, den Next.js direkt an den Browser sendet.
Hier ist das Snippet:
// 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' },
})
}
Mit diesem Handler gibt ein POST an /api/assist/stream Geminis Ausgabe als Live-Text-Stream zurück statt als einzelnen Block. Der Browser liest ihn Chunk für Chunk, was den Schreibmaschinen-Effekt in der UI erzeugt, die Sie in Schritt 4 bauen.
Fehlerbehandlung ist hier wichtig. Der Aufruf von controller.error(), wenn Gemini einen Fehler wirft, macht den Fehler im Browser sichtbar, statt den Stream stillschweigend zu schließen, was von einer leeren, erfolgreichen Antwort nicht zu unterscheiden wäre.
3. Bauen Sie den Gemini-CMS-Modus-Route-Handler in Webflow Cloud
Der CMS-Modus-Endpoint nutzt Geminis Funktion für strukturierte Ausgabe (responseMimeType: 'application/json' mit einem responseSchema), um ein JSON-Objekt zurückzugeben, das exakt auf Ihre Webflow-CMS-Felder abbildet. Die Redakteurin erhält ein Ergebnis, das sie direkt einfügen kann, ohne Umformatierung.
Hier ist der CMS-Modus-Route-Handler, der die Ausgabe an das Schema Ihrer Collection bindet:
// 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)
}
Ein Hinweis zu responseSchema: Googles API-Referenz kennzeichnet es inzwischen als veraltet, obwohl es weiterhin vollständig dokumentiert ist, kein angekündigtes Entfernungsdatum hat und mit einem kompatiblen responseMimeType kombiniert werden muss. Betrachten Sie es als etwas, das Sie später überprüfen sollten, nicht als etwas, das Sie heute umschreiben müssen.
Meiner Erfahrung nach trägt der System-Prompt mehr zur Ausgabequalität bei als alles andere in diesem Build. Ich verbringe mehr Zeit damit, die System-Instruction zu justieren (Wortzahl-Ziele anzupassen, Feldbeschreibungen hinzuzufügen, festzulegen, was „Plain Text" für ein bestimmtes CMS-Setup bedeutet), als mit dem Schreiben des Anwendungscodes.
4. Bauen Sie die UI des Gemini-Content-Assistenten
Die Client Component verwaltet den Formularstatus und den Streaming-Reader. Wenn die Redakteurin einen Prompt absendet, öffnet sie einen ReadableStream aus der Fetch-Antwort und hängt jeden decodierten Chunk an eine State-Variable an, wodurch der Schreibmaschinen-Effekt entsteht.
Hier ist die Client Component, die den Formularstatus und den Streaming-Reader verwaltet:
// 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>
)
}
Diese Komponente steuert beide Modi über ein einziges Formular. Im Entwurfsmodus liest sie den Antwort-Stream und hängt jeden Chunk an den State an, sodass Text erscheint, während er generiert wird. Im CMS-Modus wartet sie auf das vollständige JSON-Objekt und rendert dann jedes Feld mit seiner eigenen Kopier-Steuerung. Beide Pfade teilen sich dieselben Topic- und Tone-Eingaben, sodass die Redakteurin beim Wechsel des Modus nie etwas erneut eingeben muss.
5. Fügen Sie den Gemini-Content-Assistenten zu einer Webflow-Cloud-Seite hinzu
Erstellen Sie die Seite, die den Assistenten ausliefert. Da ContentAssistant eine Client Component ist, ist die Seite selbst ein Server-Component-Wrapper:
// app/content-assistant/page.tsx
import ContentAssistant from './ContentAssistant'
export default function ContentAssistantPage() {
return (
<main className="assistant-page">
<ContentAssistant />
</main>
)
}
Der Assistent ist jetzt live unter /content-assistant in Ihrer Webflow-Cloud-App. Wenn die App als Teil einer Webflow-Website deployed ist, mounten Sie ihn am Pfad, den Sie in Site Settings > Webflow Cloud konfigurieren. Der Zugriff kann mit jeder Auth-Middleware abgesichert werden; im Supabase-Auth-Leitfaden erfahren Sie, wie Sie den Assistenten auf eingeloggte Teammitglieder beschränken.
Was bringt einen Gemini-Content-Assistenten in Webflow zum Absturz?
Die meisten Fehler bei einem Gemini-Content-Assistenten lassen sich auf drei Dinge zurückführen: ein zu niedrig eingestelltes Output-Token-Limit, fehlerhaftes JSON im CMS-Modus, und einen API-Key, der lokal, aber nicht in Produktion funktioniert. Jeder Fehler tritt an einer vorhersehbaren Stelle auf, und jeder hat eine schnelle Lösung, sobald Sie die Ursache kennen.
Hier sind die einzelnen Fehlermuster.
Streaming-Antwort ist leer oder bricht mitten im Satz ab
Die häufigste Ursache ist, dass das maxOutputTokens-Limit für den angeforderten Content zu niedrig ist. Das obige Beispiel setzt es auf 1024 Token, was für einen Entwurf von 300 bis 400 Wörtern reicht.
Für längeren Content erhöhen Sie maxOutputTokens (Gemini 3.5 Flash unterstützt bis zu 65.536 Output-Token). Prüfen Sie außerdem, ob der Block finally { controller.close() } vorhanden ist; ohne ihn lässt ein Gemini-API-Fehler den Stream offen, und die UI hängt sich auf.
CMS-JSON-Ausgabe enthält zusätzlichen Text oder Markdown rund um das JSON
Das passiert, wenn responseMimeType gesetzt ist, das Modell aber trotzdem eine Erklärung hinzufügt. Übergeben Sie responseMimeType: 'application/json' in der Config immer zusammen mit responseSchema; ohne das Schema kann das Modell das JSON in Markdown-Code-Fences verpacken.
Wenn weiterhin zusätzlicher Text erscheint, fügen Sie der System-Instruction „Output only raw JSON. No explanation, no code fences." hinzu.
Der Gemini-API-Key wird in Produktion abgelehnt
Prüfen Sie, ob GEMINI_API_KEY in den Umgebungsvariablen von Webflow Cloud unter Settings > Environment Variables gesetzt ist, und nicht nur in .env.local. Lokal gesetzte Umgebungsvariablen werden nicht in die Produktion übernommen.
Prüfen Sie außerdem, ob der Key nicht das Rate-Limit der kostenlosen Stufe erreicht hat; die kostenlose Gemini-Stufe hat Generierungslimits pro Minute, die beim Testen schnell überschritten werden können.
Erweitern Sie Ihren Gemini-Content-Assistenten für Webflow-CMS-Workflows
Der Assistent in diesem Leitfaden deckt die zwei Muster ab, die ich bei jedem Projekt nutze: gestreamte Entwürfe und strukturierte CMS-Ausgabe. Beide lassen sich von hier aus problemlos erweitern.
Für mehrstufige Überarbeitung tauschen Sie den generateContent-Aufruf gegen ai.chats.create() aus und halten das Chat-Objekt über Renders hinweg in einer React-Ref. Die Redakteurin kann Gemini dann bitten, einen bestimmten Absatz umzuschreiben, den Ton zu ändern oder den Excerpt zu kürzen, ohne den ursprünglichen Kontext zu verlieren.
Entdecken Sie Webflow + Gemini für die Verbindungsoptionen, unterstützten Fähigkeiten und Setup-Hinweise, die diesem Build zugrunde liegen.
Für das Deployment von Webflow Cloud und die Environment-Konfiguration siehe die Webflow-Cloud-Dokumentation.
Häufig gestellte Fragen
Welches Gemini-Modell sollte ich verwenden?
gemini-3.5-flash ist die richtige Standardwahl für die meisten Content-Assistent-Anwendungsfälle. Es ist schnell genug für Echtzeit-Streaming, verarbeitet lange Ausgaben sauber und unterstützt strukturierte JSON-Ausgabe über den responseMimeType-Parameter. Für Content, der tieferes Reasoning oder ein größeres Context-Window benötigt, wechseln Sie zu Googles Pro-Stufe. Gemini 3.1 Pro (gemini-3.1-pro-preview) ist derzeit das über die API abrufbare Modell der Pro-Klasse, und Gemini 3.5 Pro wurde bei Google I/O 2026 angekündigt, ist aber noch nicht über die API abrufbar. Pro tauscht Geschwindigkeit gegen Tiefe des Reasonings, greifen Sie also nur darauf zurück, wenn Flash nicht ausreicht.
Läuft das @google/genai-SDK auf Webflow Cloud?
Ja. Das @google/genai-SDK nutzt die Fetch API für HTTP-Anfragen, die in der Cloudflare-Workers-Runtime verfügbar ist, auf der Webflow Cloud läuft. Fügen Sie der Route kein export const runtime = 'edge' hinzu: Next.js' Edge-Runtime wird vom OpenNext-Cloudflare-Adapter nicht unterstützt, und wenn die Direktive stehen bleibt, schlägt der Build fehl.
Kann ich den Assistenten direkt mit dem Webflow CMS verbinden, um Content zu veröffentlichen?
Nicht direkt aus dem Route Handler, aber der Weg dahin ist unkompliziert. Nachdem der CMS-Modus-Endpoint ein JSON-Objekt zurückgibt, senden Sie eine POST-Anfrage an die Webflow Data API unter https://api.webflow.com/v2/collections/{collection_id}/items, mit einem Site-Token mit dem Scope CMS:write. Das JSON von Gemini bildet auf das fieldData-Objekt im Request-Body der Webflow API ab.
Was deckt die kostenlose Gemini-Stufe ab?
Die kostenlose Stufe der Gemini API umfasst ratenbegrenzten Zugriff auf gemini-3.5-flash ohne Abrechnungspflicht. Für einen Content-Assistenten, der von einem kleinen Team genutzt wird, reicht die kostenlose Stufe in der Regel für Tests und leichte Produktionsnutzung. Anwendungsfälle mit hohem Volumen benötigen eine kostenpflichtige Stufe. Rate-Limits variieren je Nutzungsstufe und werden pro Projekt in AI Studio angezeigt, siehe daher wie Limits zugewiesen werden und die Preise pro Token für aktuelle Zahlen.
Wie verhindere ich, dass Redakteur:innen beliebige Prompts an Gemini senden?
Zwei Ansätze funktionieren gut zusammen: Validieren und bereinigen Sie das topic-Feld im Route Handler, bevor es Gemini erreicht (Zeichenlimit erzwingen, HTML-Tags entfernen), und schärfen Sie die System-Instruction so, dass sie definiert, was das Modell tun soll und was nicht. Für Teams, bei denen der Content-Scope streng kontrolliert wird, ersetzt ein Dropdown mit vordefinierten Content-Typen (Blogbeitrag, Produktbeschreibung, Ankündigung) das Freitext-Topic-Feld und hält die Generierung innerhalb der erwarteten Grenzen.


