Webflow Cloud te ofrece un servidor justo al lado de tu sitio, que es exactamente lo que necesitas para integrar el feedback de UserVoice en tu propio dominio de forma segura.
La pregunta más frecuente de los equipos que usan UserVoice junto a un sitio de marketing en Webflow es alguna variante de "¿cómo muestro nuestra hoja de ruta y lista de ideas en nuestro propio dominio en lugar de en un uservoice.com subdominio?"
La tentación es insertar la clave de API de UserVoice en un código personalizado y obtener las ideas directamente desde el navegador. Ese enfoque falla en cuanto lo publicas, porque cada línea de JavaScript del lado del cliente es visible al ver el código fuente, y una clave de API de administrador de UserVoice otorga acceso total de lectura y escritura a tu cuenta.
La solución es un pequeño servidor entre tu sitio de Webflow y UserVoice que almacene las credenciales y solo exponga las respuestas que la página necesita.
Esta guía recorre todo el proceso: el cliente de API de confianza, el intercambio de tokens, el gestor de rutas del proxy, la interfaz del portal, la sincronización con el CMS de Webflow y los webhooks firmados para actualizaciones casi en tiempo real.
¿Qué necesitas para crear un portal de feedback de UserVoice en Webflow Cloud?
Necesitas una cuenta de UserVoice con un cliente de API de confianza, una aplicación de Webflow Cloud ejecutando Next.js y permiso para instalar la aplicación de GitHub de Webflow Cloud en tu repositorio.
No hay un servidor sin servidor (serverless) independiente que aprovisionar ni SDK que instalar, ya que tanto la API de administración de UserVoice como la API de datos de Webflow son puntos finales REST sencillos a los que el entorno de ejecución en el borde puede acceder con fetch.
Aquí tienes la lista de verificación completa que sigo antes de escribir una sola línea de código:
- Una cuenta de UserVoice donde seas administrador, además de tu subdominio (el
SUBDOMAINenSUBDOMAIN.uservoice.com) - Un cliente de API de confianza en UserVoice, que te proporcione una clave de API y un secreto
- Una aplicación de Webflow Cloud ejecutando Next.js 15 o superior en el entorno de ejecución en el borde
- Una cuenta de GitHub con permiso para instalar la aplicación de GitHub de Webflow Cloud
- Permiso para crear aplicaciones en tu espacio de trabajo de Webflow
- Node.js 22 o superior instalado localmente para el desarrollo
- Una colección del CMS de Webflow si planeas replicar el feedback en el CMS (Paso 5)
Una vez que tengas todo esto, la integración consiste básicamente en mover un token de forma segura. Las secciones siguientes comienzan con el cliente de UserVoice y terminan con los webhooks, y cada paso se basa en las variables de entorno configuradas en el anterior.
6 pasos para crear un portal de feedback personalizado de UserVoice en Webflow Cloud
La compilación se divide en dos partes. La primera (pasos 1 a 4) muestra un portal en vivo en pantalla: crear el cliente de API, almacenar las credenciales en Webflow Cloud, usar un Route Handler en el edge para hacer proxy de la Admin API y renderizar las ideas en un Client Component.
La segunda parte (pasos 5 y 6) hace que el portal sea duradero y esté actualizado: refleja los comentarios en el CMS de Webflow para que sean indexables y verifica los webhooks firmados para que la página muestre las nuevas ideas sin necesidad de una resincronización completa.
Lee los pasos en orden la primera vez. El manejo de tokens en el paso 3 es la base de todo lo demás, y tanto el paso 5 como el 6 reutilizan el mismo patrón de proxy en lugar de abrir nuevas conexiones a UserVoice.
1. Crear un cliente de API de UserVoice de confianza
Comienza en la consola de administración de UserVoice, ya que la clave de API que generes aquí es la que autoriza cada llamada del lado del servidor en esta guía. Abre Settings, luego Integrations, después UserVoice API keys y haz clic en "Add API Key…". Ponle un nombre a la clave para identificarla después, deja los campos "APPLICATION URL" y "CALLBACK URL" en blanco y marca la casilla "Trusted".
Lo de "Trusted" es lo que la gente suele pasar por alto: sin ello, la clave no puede usar la concesión de credenciales de cliente de la que depende una integración servidor a servidor. Haz clic en "Add API key" para terminar.
UserVoice te mostrará dos valores: una clave de API y un secreto de API. En términos de OAuth, la clave de API es tu client_id y el secreto de API es tu client_secret. Copia ambos en un gestor de contraseñas de inmediato, porque el secreto es lo que permite a cualquiera crear tokens de administrador para tu cuenta. También necesitarás tu subdominio, que es la primera parte de tu URL de UserVoice.
Si tu portal está en acme.uservoice.com, tu subdominio es acme. Ten los tres valores a mano para el siguiente paso, donde se convertirán en variables de entorno en lugar de valores codificados de forma rígida.
2. Añadir tus credenciales a Webflow Cloud
A continuación, traslada esos tres valores a Webflow Cloud para que residan en el servidor y nunca se envíen al navegador. En la configuración de tu sitio Webflow, abre Webflow Cloud, selecciona tu aplicación y elige el entorno que estás configurando.
Abre la pestaña de variables de entorno (Environment variables), haz clic en Add Variable para cada valor y activa la opción Secret para la clave y el secreto de API.
La opción de secreto es importante porque evita que el valor aparezca en los registros de compilación y en la interfaz de lectura, que es precisamente el objetivo de no incluirlo en el código del cliente.
Añade las variables con estos nombres para que los ejemplos de código coincidan con tu configuración:
USERVOICE_SUBDOMAIN=acme
USERVOICE_CLIENT_ID=your_api_key
USERVOICE_CLIENT_SECRET=your_api_secret
USERVOICE_SSO_KEY=your_sso_key
Esos nombres no llevan intencionadamente ningún prefijo NEXT_PUBLIC_. Todo lo que tenga el prefijo NEXT_PUBLIC_ se incluye en el paquete del navegador, y estos cuatro valores deben permanecer en el lado del servidor. USERVOICE_SSO_KEY aún no es necesario, pero el paso 6 lo usa para verificar las firmas de los webhooks, así que lo añado ahora para evitar un segundo despliegue más adelante.
Refleja las mismas variables en tu archivo local .env.local para el desarrollo. Con las credenciales listas, el servidor puede autenticarse, que es lo que hace el proxy en el siguiente paso con cada solicitud.
3. Crear el token OAuth y el Route Handler de proxy
Este Route Handler es el núcleo de la integración, por lo que realiza tres tareas a la vez: intercambia tus credenciales de cliente por un token de acceso, almacena ese token en caché y reenvía una lista restringida de solicitudes de lectura a la Admin API de UserVoice.
Como se ejecuta en el entorno de ejecución edge, utiliza fetch tanto para el intercambio de tokens como para la llamada de proxy, sin necesidad de ninguna biblioteca HTTP específica de Node.
El intercambio de tokens es una única solicitud POST al endpoint de OAuth de UserVoice con la concesión de credenciales de cliente.
El manejador a continuación solicita un token, lo mantiene en una variable a nivel de aislamiento y lo reutiliza hasta que UserVoice lo rechaza con un error 401, momento en el cual limpia la caché y obtiene uno nuevo:
// app/api/uservoice/[resource]/route.ts
export const runtime = 'edge'
import { NextResponse, type NextRequest } from 'next/server'
// Only these resources can be requested through the proxy.
const ALLOWED = new Set(['suggestions', 'forums', 'statuses'])
let cachedToken: string | null = null
async function getToken(force = false): Promise<string> {
if (cachedToken && !force) return cachedToken
const sub = process.env.USERVOICE_SUBDOMAIN!
const res = await fetch(`https://${sub}.uservoice.com/api/v2/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.USERVOICE_CLIENT_ID!,
client_secret: process.env.USERVOICE_CLIENT_SECRET!,
}),
})
if (!res.ok) throw new Error(`Token request failed: ${res.status}`)
const { access_token } = (await res.json()) as { access_token: string }
cachedToken = access_token
return access_token
}
export async function GET(
request: NextRequest,
{ params }: { params: { resource: string } }
) {
const { resource } = params
if (!ALLOWED.has(resource)) {
return NextResponse.json({ error: 'Unknown resource' }, { status: 400 })
}
const sub = process.env.USERVOICE_SUBDOMAIN!
const url = `https://${sub}.uservoice.com/api/v2/admin/${resource}?per_page=50`
const call = (token: string) =>
fetch(url, { headers: { Authorization: `Bearer ${token}` } })
// Try the cached token, then refresh once on a 401.
let token = await getToken()
let upstream = await call(token)
if (upstream.status === 401) {
token = await getToken(true)
upstream = await call(token)
}
if (!upstream.ok) {
return NextResponse.json(
{ error: 'UserVoice request failed' },
{ status: upstream.status }
)
}
const data = await upstream.json()
return NextResponse.json(data)
}
La lista de permitidos es el límite de seguridad que hace que esto sea seguro de exponer. El navegador envía un nombre de recurso como suggestions, y el controlador rechaza cualquier cosa que no esté en el conjunto ALLOWED, por lo que un visitante curioso no puede reescribir la ruta para llegar a users o a un punto final de escritura.
El token nunca sale del servidor, y el reintento 401 significa que un token que UserVoice caduca o revoca activa una única actualización limpia en lugar de una avalancha de solicitudes fallidas.
Una cosa que debes saber: en el entorno de ejecución perimetral (edge runtime), el cachedToken a nivel de módulo solo dura lo que dura un aislamiento activo, por lo que con poco tráfico ocasionalmente tendrás que pagar por un intercambio de token nuevo.
Para portales más pesados, mueve la caché al almacén de clave-valor de Webflow Cloud para que el token sobreviva en el mismo almacenamiento duradero en el que se apoya una aplicación Webflow Cloud sin servidor. Con el proxy activo, el front-end puede leer datos de UserVoice sin ver nunca una credencial.
4. Renderiza el portal de comentarios en un componente de cliente
Con el proxy instalado, la interfaz del portal se convierte en una simple solicitud fetch contra tu propio dominio. El componente de cliente a continuación solicita el recurso suggestions, que UserVoice denomina ideas enviadas, y renderiza cada una con su recuento de votos.
Observa que llama a la ruta del proxy, no a uservoice.com, por lo que el navegador solo se comunica con tu propia aplicación:
'use client'
import { useEffect, useState } from 'react'
type Suggestion = {
id: number
title: string
votes_count: number
}
export function FeedbackPortal({ basePath = '' }: { basePath?: string }) {
const [ideas, setIdeas] = useState<Suggestion[]>([])
const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading')
useEffect(() => {
fetch(`${basePath}/api/uservoice/suggestions`)
.then((res) => (res.ok ? res.json() : Promise.reject(res.status)))
.then((data) => {
setIdeas(data.suggestions ?? [])
setStatus('ready')
})
.catch(() => setStatus('error'))
}, [basePath])
if (status === 'loading') return <p>Loading feedback…</p>
if (status === 'error') return <p>Could not load feedback right now.</p>
return (
<ul className="feedback-list">
{ideas.map((idea) => (
<li key={idea.id}>
<span className="votes">{idea.votes_count}</span>
<span className="title">{idea.title}</span>
</li>
))}
</ul>
)
}
El único detalle de Webflow Cloud que suele confundir a la gente es la propiedad basePath. Una aplicación Webflow Cloud se sirve bajo una ruta de montaje como /app, y las llamadas fetch del lado del cliente no incluyen ese prefijo automáticamente como lo hacen <Link> y useRouter().
Si llamas a /api/uservoice/suggestions sin la ruta base, la solicitud se resuelve contra la raíz del sitio y devuelve tu página 404 de marketing en lugar de JSON. Pasa la ruta de montaje como basePath y la solicitud fetch se resolverá correctamente tanto en desarrollo local como en producción. En este punto, ya tienes un portal funcional que lee datos en vivo de UserVoice.
Reutilizo el mismo patrón (construir una aplicación Webflow Cloud full-stack alrededor de un proxy perimetral) en la mayoría de las integraciones, y vale la pena leer el tutorial de la aplicación Webflow Cloud full-stack si deseas conocer la arquitectura general.
5. Sincroniza los comentarios de UserVoice con el CMS de Webflow
Leer directamente de UserVoice funciona para un panel de control con sesión iniciada, pero los motores de búsqueda y los modelos de lenguaje grandes no pueden ver el contenido que aparece solo después de una solicitud del lado del cliente. Para que tu hoja de ruta sea indexable, refleja cada idea en una colección del CMS de Webflow para que se renderice como HTML estático.
Aquí es donde el portal empieza a generar tráfico orgánico en lugar de solo atender a los usuarios existentes.
La sincronización es un segundo controlador de ruta que lee de UserVoice mediante la misma lógica de tokens y escribe en la API de datos de Webflow. Crea una colección con campos de name y slug además de un campo numérico para los votos, luego asigna cada sugerencia de UserVoice a un elemento del CMS.
El controlador a continuación crea elementos directamente en el sitio activo utilizando el punto final live-items de la API de datos:
// app/api/sync/route.ts
export const runtime = 'edge'
import { NextResponse, type NextRequest } from 'next/server'
export async function POST(request: NextRequest) {
// Protect the sync endpoint with a shared secret.
if (request.headers.get('authorization') !== `Bearer ${process.env.SYNC_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Read ideas through the proxy you already built.
const origin = new URL(request.url).origin
const uvRes = await fetch(`${origin}/api/uservoice/suggestions`)
const { suggestions } = (await uvRes.json()) as {
suggestions: { id: number; title: string; votes_count: number }[]
}
const fieldData = suggestions.map((s) => ({
name: s.title,
slug: `idea-${s.id}`,
votes: s.votes_count,
}))
const wfRes = await fetch(
`https://api.webflow.com/v2/collections/${process.env.WEBFLOW_COLLECTION_ID}/items/live`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WEBFLOW_SITE_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ items }),
}
)
if (!wfRes.ok) {
return NextResponse.json({ error: 'CMS write failed' }, { status: wfRes.status })
}
return NextResponse.json({ synced: items.length })
}
Vale la pena destacar dos cosas en ese controlador. Primero, la API de datos crea elementos en lugar de actualizarlos, por lo que publicar las mismas ideas de nuevo no actualiza las originales. Webflow mantiene los slugs únicos añadiendo un sufijo, lo que significa que una ejecución repetida sin control llena la colección de duplicados.
Para mantener la sincronización idempotente, almacena el ID del elemento de Webflow de cada idea, indexado por su ID de UserVoice, en el almacén de clave-valor, luego usa PATCH para actualizar el elemento existente en ejecuciones posteriores y crea solo las ideas que no hayas visto antes. Derivar una clave estable como idea-123 a partir del ID de UserVoice te permite hacer coincidir ambos.
Segundo, el controlador publica en /items/live, para que las ideas se publiquen inmediatamente, aunque puedes cambiar al punto final /items si prefieres revisar antes de publicar.
Añade WEBFLOW_COLLECTION_ID, WEBFLOW_SITE_TOKEN y SYNC_SECRET a tus variables de entorno primero. Si eres nuevo escribiendo en colecciones de esta manera, la guía de la API del CMS de Webflow cubre los tokens y el mapeo de campos con más detalle.
Una vez que se ejecuta la sincronización, tus comentarios viven en el CMS, y lo único que queda es mantenerlos actualizados.
6. Verifica webhooks firmados para actualizaciones en tiempo real
Ejecutar la sincronización con un temporizador funciona, pero o se queda atrás respecto a la realidad o satura la API. Los service hooks de UserVoice cierran esa brecha enviando un evento en el momento en que algo cambia y, dado que esas solicitudes llegan desde la internet pública, la verificación de la firma no es opcional.
Este es un punto donde la configuración de Webflow Cloud moldea el código, así que lee la explicación antes de copiarlo.
En la consola de administración de UserVoice, abre Integrations, luego Service hooks, y añade un webhook personalizado que apunte a tu controlador, eligiendo eventos como New Idea e Idea Votes Update. UserVoice firma el payload calculando HMAC-SHA256 sobre el parámetro usando tu clave SSO, y luego envía el resultado en un parámetrodatasignature
Webflow Cloud habilita la compatibilidad con Node.js de forma predeterminada, por lo que crypto.createHmac de Node está disponible si lo necesitas.
La propia guía de Webflow recomienda la Web Crypto API (crypto.subtle) para el hashing y, debido a que es un estándar de la plataforma Web, se comporta igual tanto en el desarrollo local como en el edge, por lo que esta guía realiza la verificación con ella:
// app/api/webhooks/uservoice/route.ts
export const runtime = 'edge'
import { NextResponse, type NextRequest } from 'next/server'
async function isValid(data: string, signature: string): Promise<boolean> {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(process.env.USERVOICE_SSO_KEY!),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
)
const mac = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(data))
const expected = btoa(String.fromCharCode(...new Uint8Array(mac)))
// Constant-time compare to avoid leaking timing information.
if (expected.length !== signature.length) return false
let diff = 0
for (let i = 0; i < expected.length; i++) {
diff |= expected.charCodeAt(i) ^ signature.charCodeAt(i)
}
return diff === 0
}
export async function POST(request: NextRequest) {
const form = await request.formData()
const data = String(form.get('data') ?? '')
const signature = String(form.get('signature') ?? '')
if (!(await isValid(data, signature))) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 })
}
const event = JSON.parse(data)
// Trigger a targeted re-sync or cache purge here using `event`.
return NextResponse.json({ received: true })
}
La comprobación de la firma vuelve a calcular el HMAC con y lo compara con lo que envió UserVoice; el bucle manual byte a byte es una comparación de tiempo constante que evita el canal lateral de temporización que abriría un ingenuo.crypto.subtle.sign===
La razón para recurrir a aquí es que forma parte de la plataforma Web y se comporta igual en cualquier lugar donde se ejecute tu código, lo que mantiene el verificador portátil entre el desarrollo local, el edge y cualquier otro entorno de ejecución al que lo traslades más tarde.crypto.subtle
Una vez que la firma es válida, puedes analizar el payload y actualizar solo la idea afectada en lugar de volver a sincronizar toda la colección. Eso te mantiene cómodamente dentro de los límites de tasa de la API, que es el modo de fallo con el que comienza la siguiente sección.data
¿Qué rompe una integración entre UserVoice y Webflow Cloud?
La mayoría de los fallos provienen de cuatro lugares predecibles: la casilla de confianza (trusted) nunca se marcó, por lo que se rechazan los tokens; no se añadió una variable de entorno al entorno desplegado; una sincronización masiva superó un límite de tasa; o se eliminó la ruta base de una petición del cliente.
Cada uno produce un síntoma distinto y ninguno es sutil una vez que sabes dónde buscar.
La lista a continuación empareja el síntoma que verás realmente con la causa y la solución, en el orden en que suelo encontrarlos en una nueva compilación.
La solicitud de token devuelve 401 invalid_client
Si el intercambio de tokens OAuth falla con , al cliente de la API casi siempre le falta la marca de confianza (trusted). UserVoice solo permite la concesión de credenciales de cliente para clientes creados con "Trusted" marcado, por lo que una clave generada sin esto se autentica para flujos interactivos pero no para llamadas de servidor a servidor.invalid_client
Elimina la clave, crea una nueva y confirma que la casilla "Trusted" esté marcada antes de guardar. La otra causa común es un error de copiar y pegar en el secreto, ya que un espacio al final sobrevive al pegarse en una variable de entorno y rompe la coincidencia silenciosamente.
Vuelve a introducir el valor manualmente en la pestaña de variables de entorno de Webflow Cloud, vuelve a desplegar y el intercambio de tokens debería tener éxito.USERVOICE_CLIENT_SECRET
El proxy funciona localmente pero devuelve un 500 en Webflow Cloud
Cuando un controlador funciona bien en el desarrollo local y luego devuelve un 500 en producción, la causa más común es una variable de entorno que existe en tu local pero que nunca se añadió al entorno desplegado, o que se añadió a un entorno diferente al que sirve el tráfico..env.local
El intercambio de tokens en el paso 3 lanza un error cuando o no están definidos, y eso aparece como un 500. Abre Webflow Cloud, selecciona el entorno que está activo y confirma que todas las variables del paso 2 estén presentes, con la clave de API y el secreto marcados como secretos.USERVOICE_CLIENT_IDUSERVOICE_CLIENT_SECRET
El módulo de crypto Node, incluidos crypto.createHmac y crypto.timingSafeEqual, está disponible en Webflow Cloud porque la compatibilidad con Node.js está habilitada de forma predeterminada, por lo que es mucho más probable que falte una variable a que una API no sea compatible.
Conectar el proxy al seguimiento de errores de Sentry permite visualizar estos fallos en tiempo de ejecución con un seguimiento de pila en lugar de un simple error 500.
UserVoice devuelve un error 429 durante una sincronización del CMS
Un error 429 de UserVoice significa que has superado el límite de solicitudes para el minuto actual. UserVoice no publica una cifra fija porque el límite depende de tu plan, pero lo devuelve en tiempo real en el encabezado X-Rate-Limit-Limit, el recuento restante en X-Rate-Limit-Remaining, y un valor Retry-After cuando te pasas.
La solución es dejar de hacer una solicitud por cada idea. Aumenta per_page para que una sola llamada devuelva hasta cincuenta o cien registros, utiliza la carga lateral (side-loading) para obtener registros asociados en la misma respuesta y, cuando recibas un 429, lee Retry-After, que UserVoice devuelve como una marca de tiempo Unix en segundos, y espera hasta ese momento antes de volver a intentarlo en lugar de entrar en un bucle inmediato.
El enfoque de webhooks del paso 6 evita esto por completo en las actualizaciones, ya que vuelves a sincronizar una sola idea modificada en lugar de toda la lista.
El portal carga, pero la lista de comentarios está vacía
Si el componente se renderiza pero no muestra ideas, abre la pestaña de red de tu navegador y comprueba la solicitud a /api/uservoice/suggestions. Una respuesta que sea HTML en lugar de JSON, o un error 404, indica que falta una ruta base: la recuperación se resolvió en la raíz del sitio en lugar de en la ruta de montaje de tu aplicación de Webflow Cloud.
Pasa la ruta de montaje de la aplicación al componente como basePath, tal como se indica en el paso 4, para que la solicitud llegue a tu gestor de rutas (Route Handler).
Si la respuesta es un JSON válido pero la matriz está vacía, confirma que el recurso esté escrito como suggestions y que el foro contenga realmente ideas públicas, ya que UserVoice limita las sugerencias a foros y una instancia nueva puede devolver legítimamente un conjunto vacío.
Lleva el portal más allá con SSO y búsqueda
En este punto, ya tienes un portal de comentarios en tu propio dominio, indexado en el CMS y actualizado mediante webhooks firmados. El siguiente paso natural depende de a quién vaya dirigido tu portal. Si es un portal para clientes registrados, querrás implementar el inicio de sesión único (SSO) para que los visitantes sean reconocidos sin necesidad de volver a iniciar sesión.
UserVoice admite SSO mediante JWT firmado con HS256 usando la misma clave SSO del paso 6, incluyendo una declaración guid y email, y una biblioteca compatible con el edge como jose firma ese token dentro de un gestor de rutas sin ninguna dependencia de Node.
Enrutar tu sesión existente hacia ese token sigue el mismo patrón que cualquier flujo de autenticación de Auth0 que ya puedas estar utilizando.
Si el portal es público y tiene mucho contenido, prioriza el descubrimiento. Una vez que las ideas estén en el CMS, añadir una búsqueda de texto completo sobre la colección permite a los visitantes encontrar solicitudes previas antes de enviar duplicados, y una vista de panel en tiempo real convierte los votos en bruto en algo que un equipo de producto realmente consultará.
Si tu portal también acepta nuevas ideas a través de un formulario de Webflow, añade protección contra spam reCAPTCHA antes de que esos envíos lleguen a UserVoice. Para cualquier cosa que vaya más allá de lo que cubren estos gestores de rutas, la guía de API de código personalizado y la documentación para desarrolladores de Webflow cubren todo el espectro, desde la gestión de webhooks hasta las operaciones masivas en el CMS.
Preguntas frecuentes
¿Por qué no puedo llamar a la API de UserVoice directamente desde el código personalizado de Webflow?
Porque el código personalizado de Webflow se ejecuta completamente en el navegador, y cualquier clave de API que insertes allí será visible al ver el código fuente. Una clave de API de administrador de UserVoice otorga acceso total a la cuenta, por lo que debe permanecer en un servidor. Webflow Cloud te proporciona ese servidor dentro del mismo proyecto.
¿Necesito un plan de pago de UserVoice para acceder a la API?
El acceso a la API y su límite de velocidad dependen de tu plan de UserVoice y de los términos de servicio, no de una cifra única publicada. Confirma tus límites actuales en tu cuenta, ya que la API de administración devuelve tu límite en tiempo real en el encabezado de respuesta X-Rate-Limit-Limit en cada solicitud.
¿Puedo ejecutar esto en Astro en lugar de Next.js?
Sí. Webflow Cloud es compatible con Astro 6 y 7, además de Next.js 15 o superior. La lógica del proxy es idéntica, ya que depende de y de la Web Crypto API, no de ninguna función específica del framework. Solo cambian la ubicación del archivo de ruta y la firma del controlador.fetch
¿Por qué mi controlador de webhooks falla solo en producción?
Lo más probable es que falte una variable de entorno necesaria en el entorno desplegado. Es posible que tu esté en tu local pero nunca se haya añadido en Webflow Cloud, por lo que la verificación de firma solo falla en producción. Asegúrate de que todas las variables del paso 2 existan en el entorno real. El módulo de Node es compatible con Webflow Cloud, así que rara vez es la causa.USERVOICE_SSO_KEY.env.localcrypto
¿Cómo evito que el CMS se llene de ideas duplicadas?
La API de datos crea elementos en lugar de actualizarlos por slug, por lo que volver a publicar las mismas ideas generará duplicados. Mantén un mapa de cada ID de UserVoice con su ID de elemento de Webflow en el almacén de clave-valor; así podrás usar PATCH para actualizar el elemento existente en ejecuciones posteriores y crear solo las ideas que aún no hayas sincronizado.
¿Debo sincronizar según un horario o usar webhooks?
Usa webhooks para las actualizaciones y deja el horario solo como red de seguridad. Los webhooks envían cada cambio al instante, lo que te permite resincronizar una sola idea y mantenerte muy por debajo del límite de tasa. Una sincronización completa nocturna se encargará de capturar cualquier cosa que un webhook perdido haya dejado atrás.





