Una colección de Webflow CMS en crecimiento necesita dos cosas a la vez: búsquedas rápidas e imágenes con el tamaño adecuado, y puedes añadir ambas a una aplicación Webflow Cloud usando solo Route Handlers y fetch.
Cuando una colección de Webflow CMS supera unos pocos cientos de elementos, surgen dos necesidades simultáneas. Los visitantes requieren una búsqueda rápida para encontrar el elemento correcto, y las imágenes deben entregarse en el formato y tamaño adecuados para cada dispositivo. Algolia se encarga de la búsqueda, Cloudinary de los medios, y ambos encajan perfectamente en una aplicación Webflow Cloud que se ejecuta en el entorno de Workers.
Ambas herramientas se integran limpiamente en el entorno de Workers de Webflow Cloud. El cliente JavaScript v5 de Algolia incluye una compilación específica para workers que utiliza la API Fetch, por lo que funciona en un Route Handler sin necesidad de modificar la capa HTTP. Las transformaciones de URL de Cloudinary no requieren SDK; se realizan en el borde de la CDN de Cloudinary cuando se solicita la URL. El Route Handler de carga utiliza fetch frente a la API REST de Cloudinary.
Las siguientes secciones explican cómo configurar ambos, comenzando con el índice de Algolia y terminando con la carga de imágenes optimizadas.
¿Qué necesitas para añadir la búsqueda de Algolia y la optimización de medios de Cloudinary a una aplicación Webflow Cloud?
Necesitas un proyecto Webflow Cloud Next.js, una cuenta de Algolia con un índice y una cuenta de Cloudinary. Ambas herramientas ofrecen niveles gratuitos que funcionan para el desarrollo y para entornos de producción con poco tráfico.
Aquí tienes la lista completa:
- Un proyecto de Webflow Cloud ejecutando una aplicación Next.js, ya sea desplegada o en desarrollo local
- Una cuenta de Algolia con una aplicación y un índice (algolia.com)
- Una cuenta de Cloudinary con un ajuste preestablecido de carga configurado (cloudinary.com)
- Un token de sitio de Webflow con alcance
cms:read(para sincronizar el contenido del CMS con Algolia) - Node.js 22.13.0 o superior de forma local, el requisito mínimo para Webflow CLI 2.0
Una vez que tengas todo esto listo, puedes comenzar la integración completa.
6 pasos para añadir la búsqueda de Algolia y la optimización de medios de Cloudinary a una aplicación Webflow Cloud
El modelo se divide en dos capacidades independientes. Algolia gestiona la búsqueda: un Route Handler de sincronización indexa el contenido de tu Webflow CMS, y un Route Handler de proxy de búsqueda mantiene tu clave de API de administrador en el lado del servidor mientras el navegador realiza las consultas de búsqueda.
Cloudinary gestiona los medios: una utilidad de URL genera enlaces de imágenes optimizadas sin peticiones adicionales, y un Route Handler de carga acepta los archivos subidos por el cliente y devuelve el ID público de Cloudinary para su almacenamiento.
1. Crea un índice de Algolia y obtén tus credenciales
Inicia sesión en algolia.com y ve a Search > Indices. Haz clic en Create Index y asígnale un nombre que coincida con tu contenido (por ejemplo, webflow-blog-posts). Copia el nombre del índice; lo necesitarás como variable de entorno.
Ve a Settings > API Keys. Utilizarás dos claves diferentes:
- Admin API Key: Otorga acceso completo de lectura y escritura. Úsala solo en el Route Handler de sincronización del CMS. Nunca la expongas al navegador.
- Search-Only API Key: Acceso de solo lectura para realizar búsquedas. Esta clave es segura para usar en un endpoint de proxy de búsqueda (aunque, incluso en este caso, es una buena práctica mantenerla en el lado del servidor).
Añade todas las credenciales a .env.local y a la configuración de variables de entorno de Webflow Cloud:
ALGOLIA_APP_ID=YOUR_APP_ID
ALGOLIA_ADMIN_API_KEY=your_admin_api_key
ALGOLIA_SEARCH_API_KEY=your_search_only_api_key
ALGOLIA_INDEX_NAME=webflow-blog-posts
Ninguna de ellas necesita un prefijo NEXT_PUBLIC_. Todas las operaciones de Algolia en esta guía se ejecutan en Route Handlers en el lado del servidor.
A continuación, instala el cliente JavaScript v5 de Algolia:
npm install algoliasearch@5
El cliente v5 incluye compilaciones independientes para navegador, Node.js y worker, y selecciona entre ellas según la condición de exportación. La compilación para worker utiliza la API Fetch, que es la que se aplica en Webflow Cloud.
2. Crea un Route Handler de sincronización de CMS con Algolia en Webflow Cloud
El endpoint de sincronización obtiene tu colección de CMS de Webflow y la indexa en Algolia. Lo llamarás cada vez que cambie el contenido del CMS: manualmente durante el desarrollo, o mediante un webhook de Webflow en collection_item_created y collection_item_changed en producción.
Aquí tienes el fragmento:
// app/api/algolia/sync/route.ts
import { algoliasearch } from 'algoliasearch'
import { NextResponse, type NextRequest } from 'next/server'
type WebflowCmsItem = {
id: string
fieldData: {
name: string
slug: string
excerpt?: string
'post-body'?: string
[key: string]: unknown
}
}
export async function POST(request: NextRequest) {
// Protect the sync endpoint with a shared secret.
const authHeader = request.headers.get('authorization')
if (authHeader !== `Bearer ${process.env.SYNC_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Fetch all CMS items from Webflow.
const cmsResponse = await fetch(
`https://api.webflow.com/v2/collections/${process.env.WEBFLOW_COLLECTION_ID}/items?limit=100`,
{
headers: {
Authorization: `Bearer ${process.env.WEBFLOW_SITE_TOKEN}`,
},
}
)
if (!cmsResponse.ok) {
return NextResponse.json(
{ error: 'Failed to fetch Webflow CMS' },
{ status: 502 }
)
}
const { items } = await cmsResponse.json() as { items: WebflowCmsItem[] }
// Map CMS items to Algolia objects.
// objectID must be unique; use the Webflow item ID.
const objects = items.map((item) => ({
objectID: item.id,
name: item.fieldData.name,
slug: item.fieldData.slug,
excerpt: item.fieldData.excerpt ?? '',
}))
// Index to Algolia using the admin key.
const client = algoliasearch(
process.env.ALGOLIA_APP_ID!,
process.env.ALGOLIA_ADMIN_API_KEY!
)
await client.saveObjects({
indexName: process.env.ALGOLIA_INDEX_NAME!,
objects,
})
return NextResponse.json({ synced: objects.length })
}
Añade SYNC_SECRET y WEBFLOW_COLLECTION_ID a tus variables de entorno. El WEBFLOW_COLLECTION_ID es visible en el Diseñador de Webflow en CMS > Configuración de la colección > ID de la colección.
Ejecuta tu primera sincronización manualmente para confirmar que funciona:
curl -X POST https://your-app.webflow.io/api/algolia/sync \
-H "Authorization: Bearer your_sync_secret"
Revisa el panel de Algolia en Search > Indices > [tu-índice] para confirmar que los registros aparecen.
3. Crea un Route Handler de proxy de búsqueda de Algolia en Webflow Cloud
El proxy de búsqueda mantiene tu clave de API de Algolia en el lado del servidor y te ofrece un único endpoint para añadir límites de tasa o validación de consultas antes de que se ejecute la búsqueda.
El manejador a continuación lee los parámetros de consulta q y page, ejecuta la búsqueda en tu índice con la clave de solo búsqueda y devuelve únicamente los campos que necesita el navegador:
// app/api/search/route.ts
import { algoliasearch } from 'algoliasearch'
import { NextResponse, type NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const query = searchParams.get('q') ?? ''
const page = parseInt(searchParams.get('page') ?? '0', 10)
if (!query.trim()) {
return NextResponse.json({ hits: [], nbHits: 0, page: 0, nbPages: 0 })
}
const client = algoliasearch(
process.env.ALGOLIA_APP_ID!,
process.env.ALGOLIA_SEARCH_API_KEY!
)
const { results } = await client.search({
requests: [
{
indexName: process.env.ALGOLIA_INDEX_NAME!,
query,
hitsPerPage: 10,
page,
},
],
})
// results[0] is a SearchResponse; cast to expose the fields we need.
const result = results[0] as {
hits: unknown[]
nbHits: number
page: number
nbPages: number
}
return NextResponse.json({
hits: result.hits,
nbHits: result.nbHits,
page: result.page,
nbPages: result.nbPages,
})
}
El endpoint de búsqueda ya está disponible en /api/search?q=your-query&page=0.
Desde cualquier componente de cliente en tu aplicación de Webflow Cloud:
// In a Client Component
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
const { hits, nbHits } = await res.json()
Como cada consulta pasa por tu propio endpoint, la clave de Algolia nunca llega al navegador, y tienes un lugar centralizado para añadir límites de tasa o comprobaciones de autenticación antes de que la solicitud llegue a Algolia. Con la indexación y la búsqueda funcionando, los siguientes pasos se centran en los archivos multimedia.
4. Conecta Cloudinary a tu aplicación de Webflow Cloud
Inicia sesión en cloudinary.com. Tu nombre de nube (Cloud name) aparece en la página principal del panel. Cópialo.
Para permitir la carga de archivos desde tu Route Handler de Webflow Cloud, crea un ajuste preestablecido de carga (upload preset) sin firmar:
- Ve a Settings > Upload > Upload presets.
- Haz clic en Add upload preset.
- Establece el modo de firma (Signing mode) en Sin firmar (Unsigned).
- Opcionalmente, define una carpeta (p. ej., ) para organizar las subidas.
webflow-cloud - Guarda y copia el nombre del ajuste preestablecido.
Añade ambos a tus variables de entorno:
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_UPLOAD_PRESET=webflow_unsigned
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_CLOUD_NAMEse utiliza en el gestor de rutas para las subidas. se puede exponer públicamente sin riesgo: el nombre de la nube no es un secreto; solo identifica la cuenta de Cloudinary de la que se obtienen las imágenes.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME
No hay ningún paquete que instalar para la utilidad de transformación. Tampoco para el gestor de rutas de subida; ambos utilizan estándar.fetch
5. Optimiza imágenes con transformaciones de URL de Cloudinary en Webflow Cloud
Cloudinary aplica transformaciones a nivel de URL. Construyes la URL en una función de utilidad; Cloudinary procesa la transformación en la primera solicitud y la sirve desde la caché de la CDN en todas las solicitudes posteriores. Sin SDK, sin sobrecarga en tiempo de ejecución.
Crea una utilidad lib/cloudinary.ts:
// lib/cloudinary.ts
type TransformOptions = {
width?: number
height?: number
crop?: 'fill' | 'fit' | 'scale' | 'thumb' | 'pad'
quality?: 'auto' | number
format?: 'auto' | 'webp' | 'avif' | 'jpg' | 'png'
aspectRatio?: string
}
export function cloudinaryUrl(
publicId: string,
options: TransformOptions = {}
): string {
const cloudName = process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME!
const transforms: string[] = []
if (options.width) transforms.push(`w_${options.width}`)
if (options.height) transforms.push(`h_${options.height}`)
if (options.crop) transforms.push(`c_${options.crop}`)
if (options.aspectRatio) transforms.push(`ar_${options.aspectRatio}`)
if (options.quality) transforms.push(`q_${options.quality}`)
if (options.format) transforms.push(`f_${options.format}`)
const transformStr = transforms.length > 0 ? transforms.join(',') + '/' : ''
return `https://res.cloudinary.com/${cloudName}/image/upload/${transformStr}${publicId}`
}
Utiliza la función en cualquier parte de tu aplicación de Webflow Cloud:
// A responsive hero image: 1200px wide, auto format, auto quality
const heroUrl = cloudinaryUrl('blog/hero-image', {
width: 1200,
format: 'auto',
quality: 'auto',
})
// → https://res.cloudinary.com/your-cloud/image/upload/w_1200,f_auto,q_auto/blog/hero-image
// A square thumbnail with cropping
const thumbUrl = cloudinaryUrl('products/sneaker-01', {
width: 400,
height: 400,
crop: 'fill',
format: 'auto',
quality: 'auto',
})
// → https://res.cloudinary.com/your-cloud/image/upload/w_400,h_400,c_fill,f_auto,q_auto/products/sneaker-01
f_autoes la transformación individual más importante en la mayoría de los proyectos: Cloudinary detecta la compatibilidad del navegador y sirve AVIF o WebP cuando está disponible, recurriendo a JPEG en caso contrario. ajusta la compresión de cada imagen según su tipo de contenido. Juntos, reducen la carga útil de la imagen considerablemente sin cambios visibles en la calidad.q_auto
El es el identificador que devuelve Cloudinary cuando se sube una imagen (tratado en el paso 6). Para las imágenes que ya están en Cloudinary, el ID público es visible en la biblioteca multimedia.publicId
6. Crea un gestor de rutas de subida a Cloudinary en Webflow Cloud
El gestor de rutas de subida acepta un archivo desde un formulario de componente de cliente, lo reenvía a Cloudinary y devuelve el ID público y la URL para almacenarlos en tu aplicación o en el CMS de Webflow.
// app/api/upload/route.ts
import { NextResponse, type NextRequest } from 'next/server'
type CloudinaryUploadResult = {
secure_url: string
public_id: string
width: number
height: number
format: string
error?: { message: string }
}
export async function POST(request: NextRequest) {
const formData = await request.formData()
const file = formData.get('file') as File | null
if (!file) {
return NextResponse.json({ error: 'No file provided' }, { status: 400 })
}
// Enforce reasonable file size limits before sending to Cloudinary.
const MAX_SIZE = 10 * 1024 * 1024 // 10 MB
if (file.size > MAX_SIZE) {
return NextResponse.json({ error: 'File too large (max 10 MB)' }, { status: 413 })
}
const cloudName = process.env.CLOUDINARY_CLOUD_NAME!
const uploadPreset = process.env.CLOUDINARY_UPLOAD_PRESET!
const uploadData = new FormData()
uploadData.append('file', file)
uploadData.append('upload_preset', uploadPreset)
// Optionally set a folder for organization.
uploadData.append('folder', 'webflow-cloud')
const response = await fetch(
`https://api.cloudinary.com/v1_1/${cloudName}/image/upload`,
{
method: 'POST',
body: uploadData,
}
)
const result = await response.json() as CloudinaryUploadResult
if (!response.ok) {
return NextResponse.json(
{ error: result.error?.message ?? 'Upload failed' },
{ status: response.status }
)
}
return NextResponse.json({
url: result.secure_url,
publicId: result.public_id,
width: result.width,
height: result.height,
format: result.format,
})
}
Desde un componente de cliente, la subida es una petición estándar:FormData
// In a Client Component
async function uploadImage(file: File) {
const formData = new FormData()
formData.append('file', file)
const res = await fetch('/api/upload', {
method: 'POST',
body: formData,
})
const { publicId, url } = await res.json()
// publicId can now be stored in Webflow CMS or your app's KV Store.
// url is the direct Cloudinary URL for immediate use.
}
El devuelto es lo que pasas a en el paso 5. Una vez almacenado, puedes generar cualquier tamaño o formato a partir del original sin necesidad de volver a subirlo.publicIdcloudinaryUrl()
¿Qué puede estropear la búsqueda de Algolia y la optimización de medios de Cloudinary en Webflow Cloud?
La mayoría de los fallos aquí se deben a unas pocas causas previsibles: falta de atributos de búsqueda en el índice de Algolia, una variable de entorno que no coincide entre el entorno local y el desplegado, un ajuste preestablecido de subida con un nombre incorrecto o configurado como firmado, o un navegador que no admite WebP.
Cada punto a continuación empareja el síntoma que verás con su causa y su solución.
Algolia no devuelve resultados tras sincronizar el contenido del CMS
Abre el panel de control de Algolia en Search > Indices > [tu-indice] > Browse. Si hay registros presentes pero la búsqueda no devuelve nada, comprueba los atributos de búsqueda. Algolia indexa los registros por defecto, pero no sabe qué campos debe buscar.
Ve a Configuration > Searchable attributes y añade los campos que quieras buscar (por ejemplo, name, excerpt). Guarda la configuración y vuelve a realizar una búsqueda.
El Route Handler de sincronización devuelve un 401
El Authorization: Bearer [SYNC_SECRET] valor del encabezado debe coincidir exactamente con lo que hay en las variables de entorno de Webflow Cloud. Comprueba si hay espacios al final o problemas de codificación de caracteres al copiar el secreto.
Confirma que la variable esté configurada en Settings > Environment Variables (no solo en .env.local) para el entorno desplegado.
La carga en Cloudinary devuelve un 400 o "upload preset not found"
El nombre del ajuste preestablecido de carga en CLOUDINARY_UPLOAD_PRESET debe coincidir exactamente con el nombre en Cloudinary Settings > Upload > Upload presets. Los nombres de los ajustes distinguen entre mayúsculas y minúsculas.
Confirma también que el modo de firma (Signing mode) del ajuste esté configurado como Unsigned; los ajustes firmados requieren una marca de tiempo y una firma que este Route Handler no genera.
Las imágenes de Cloudinary muestran el formato original en lugar de WebP
El navegador no está enviando un encabezado Accept que incluya image/webp media type. Esto ocurre en navegadores antiguos y en algunos clientes de fetch headless. Para imágenes renderizadas en el servidor en Next.js, el componente <Image> gestiona la negociación de formato automáticamente.
Para las URL obtenidas desde el cliente, verifica que f_auto esté presente en la cadena de transformación.
Amplía la búsqueda de Algolia y la optimización de medios de Cloudinary en tu aplicación de Webflow Cloud
La configuración de esta guía cubre los flujos principales: indexación de CMS, proxy de búsqueda, transformación de imágenes y carga. Ambos se pueden ampliar fácilmente a partir de aquí.
Para Algolia, el siguiente paso en la mayoría de los proyectos es añadir búsqueda por facetas: filtros por categoría o fecha que acotan los resultados sin necesidad de una consulta de texto completo. Las facetas de Algolia se configuran en Configuration > Facets en el índice, y el Route Handler de búsqueda pasa facetFilters en el cuerpo de la solicitud junto con query.
Explora Webflow + Algolia para obtener un desglose completo de los enfoques de integración, desde InstantSearch en el frontend hasta pipelines de sincronización basados en webhooks.
Explora Webflow + Cloudinary para conocer las plantillas y los parámetros de URL que controlan el formato y el recorte una vez que tus archivos multimedia residen en la CDN de Cloudinary.
Preguntas frecuentes
¿Es algoliasearch v5 compatible con el entorno de ejecución Workers de Webflow Cloud?
Sí. La v5 publica una compilación para workers que utiliza la API Fetch, y los bundlers destinados a Cloudflare Workers la detectan automáticamente. Cloudflare Workers es el entorno de ejecución que impulsa Webflow Cloud. En la v4, el cliente utilizaba una compilación XHR en navegadores y una compilación http de Node.js en Node, por lo que ejecutarlo en Workers implicaba pasar un solicitante fetch manualmente. Usa la v5: npm install algoliasearch@5.
¿Puedo exponer mi clave de API de solo búsqueda (Search-Only) de Algolia en el código del lado del cliente?
La clave de API de solo búsqueda de Algolia está limitada a operaciones de lectura y no puede modificar tu índice. La documentación de Algolia permite explícitamente el uso de esta clave en el lado del cliente. Dicho esto, el patrón de proxy del paso 3 sigue siendo preferible para Webflow Cloud, ya que te permite añadir límites de tasa y validación de consultas en un solo lugar sin tener que enviar esa lógica al navegador.
¿Qué tamaño pueden tener los registros de Algolia?
El límite de tamaño de registro de Algolia depende de tu plan. El plan gratuito Build limita cada registro a 10 KB, mientras que los planes de pago elevan ese tope hasta los 100 KB. En cualquier caso, evita indexar el cuerpo completo de las entradas del CMS de Webflow si son muy largas. Indexa mejor el nombre, el slug, el extracto y las etiquetas, y recupera el contenido completo desde el CMS de Webflow cuando el usuario haga clic en un resultado de búsqueda. Especialmente en el plan gratuito, esto ayuda a mantener cada registro por debajo del límite de 10 KB.
¿Necesito configurar una carga firmada de Cloudinary en lugar de una no firmada?
Las cargas no firmadas funcionan bien para la mayoría de los casos de uso en Webflow Cloud. Solo requieren un ajuste preestablecido de carga y no suponen una carga adicional por firmas de solicitud. Si necesitas controlar lo que se sube (por ejemplo, restringir tipos de archivo o aplicar transformaciones al momento de la carga) sin exponer esas reglas al cliente, utiliza cargas firmadas. Las cargas firmadas requieren una firma del lado del servidor usando api_secret y una marca de tiempo. Consulta la documentación sobre cargas firmadas de Cloudinary.
¿Cloudinary almacena en caché las imágenes transformadas?
Sí. Cloudinary genera la versión transformada en la primera solicitud y la almacena en caché en el borde de su CDN para todas las solicitudes posteriores. El coste de procesamiento de la transformación solo ocurre una vez por cada URL única. Por eso el modelo de transformación basado en URL es viable en producción: tras la primera solicitud, los siguientes usuarios obtienen la versión almacenada en caché a toda velocidad, sin tiempo de procesamiento por parte de Cloudinary.
¿Cómo sincronizo automáticamente los cambios del CMS de Webflow con Algolia?
Registra un webhook de Webflow para collection_item_created y collection_item_changed que apunte a la URL de tu gestor de rutas de sincronización. En el gestor, en lugar de sincronizar toda la colección en cada llamada, analiza el payload del webhook para obtener el ID del elemento modificado, recupera ese único elemento de la API de datos de Webflow y llama a client.saveObjects solo con ese registro. Esto mantiene la sincronización rápida incluso en colecciones grandes.





