Cómo añadir una búsqueda con autocompletado a Webflow con Elasticsearch en Webflow Cloud

Cómo añadir búsqueda con autocompletado a Webflow usando Elasticsearch en Webflow Cloud

Aprende a añadir una búsqueda con autocompletado mientras escribes en Webflow usando el campo search_as_you_type de Elasticsearch y un Route Handler de Webflow Cloud.

Cómo añadir búsqueda con autocompletado a Webflow usando Elasticsearch en Webflow Cloud

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

Escribir una consulta completa y esperar los resultados parece algo del pasado cuando cualquier otra aplicación sugiere respuestas sobre la marcha. Aquí te mostramos cómo llevar esa misma respuesta instantánea a un sitio de Webflow que ya utiliza Elasticsearch en Webflow Cloud.

La búsqueda de texto completo de Elasticsearch responde a la consulta después de que el usuario la envía. El autocompletado responde mientras escribe, mostrando sugerencias coincidentes con cada pulsación de tecla.

Si ya has creado una búsqueda de texto completo con Elasticsearch en Webflow Cloud, la mejora de autocompletado es un cambio adicional. Un nuevo tipo de campo en el mapeo de tu índice, un endpoint de Route Handler dedicado y un controlador de entrada con debounce y control de aborto en el frontend de Webflow. No reconstruyes lo que ya tienes. Lo amplías.

En esta guía, veremos cómo migrar tu índice al search_as_you_type mapeo, reindexar tu contenido existente, crear un Route Handler de autocompletado dedicado y configurar una entrada con debounce y control de aborto en el frontend de Webflow.

¿Qué necesitas para añadir una búsqueda con autocompletado de Elasticsearch a Webflow Cloud?

Necesitas un clúster de Elastic Cloud con un índice de CMS de Webflow existente, una aplicación Next.js en Webflow Cloud con soporte para Route Handler y un token de la API de datos de Webflow con el cms:read ámbito.

Aquí tienes la lista completa.

Un clúster de Elasticsearch en Elastic Cloud

Tu clúster debe existir en Elastic Cloud y tener al menos un índice ya creado. Añadir search_as_you_type a un campo que anteriormente estaba mapeado como text requiere crear un nuevo índice con el mapeo actualizado y reindexar tu contenido, lo cual cubren los pasos 1 y 2.

Si estás creando un índice nuevo sin mapeo previo, puedes definir title como search_as_you_type desde el principio y saltarte el paso de migración por completo.

Necesitas dos claves de API de la consola de Elastic Cloud en Management y luego API Keys: una clave de solo lectura para el Route Handler que gestiona las consultas de autocompletado en vivo, y una clave con permisos de escritura para el script de indexación local que rellena el índice desde tu CMS de Webflow. Mantenlas separadas.

Una clave de solo lectura filtrada expone tus resultados de búsqueda a consultas externas. Una clave de escritura filtrada puede corromper o eliminar todo el índice. La clave de lectura se almacena en las variables de entorno de Webflow Cloud. La clave de escritura permanece en .env.local y nunca se despliega.

Una aplicación Next.js en Webflow Cloud con al menos un Route Handler

Necesitas un proyecto de Next.js desplegado en Webflow Cloud o, como mínimo, inicializado localmente con la CLI de Webflow. Si este es tu primer proyecto en Webflow Cloud, la guía de inicio de Webflow Cloud te explica cómo crear un proyecto a partir de una plantilla inicial en menos de diez minutos.

Si estás añadiendo servicios adicionales en el mismo proyecto junto al endpoint de búsqueda, crear una aplicación full-stack en Webflow Cloud con Supabase, Auth0 y Stripe cubre cómo esas integraciones coexisten en una sola aplicación de Next.js.

5 pasos para añadir una búsqueda con autocompletado de Elasticsearch a Webflow Cloud

La implementación añade un search_as_you_type campo a un nuevo índice, ejecuta una reindexación para rellenar los subcampos shingle, crea un Route Handler de autocompletado dedicado y conecta la entrada del frontend con debounce y control de aborto.

Estos pasos asumen que tienes una configuración de Elasticsearch existente de la guía de búsqueda de texto completo. Si empiezas desde cero, completa primero esa guía y vuelve aquí una vez que el endpoint de búsqueda de texto completo esté funcionando.

Vamos paso a paso.

1. Crea un nuevo índice de Elasticsearch con el mapeo de campo search_as_you_type

Elasticsearch no permite modificar el tipo de un campo en un índice existente. Si tu title campo estaba mapeado previamente como text, no puedes cambiarlo a search_as_you_type directamente. La solución es crear un nuevo índice con el mapeo actualizado y volver a indexar tu contenido en él. El script de indexación del paso 2 gestiona la migración de datos en un solo comando.

Ejecuta lo siguiente en Kibana Dev Tools, accesible desde tu consola de despliegue de Elastic Cloud, o envíalo como una solicitud curl desde tu terminal:

PUT /webflow-content-v2
{
  "mappings": {
    "properties": {
      "title": {
        "type": "search_as_you_type",
        "max_shingle_size": 3
      },
      "slug":            { "type": "keyword" },
      "body":            { "type": "text"    },
      "excerpt":         { "type": "text"    },
      "category":        { "type": "keyword" },
      "tags":            { "type": "keyword" },
      "published_at":    { "type": "date"    },
      "webflow_item_id": { "type": "keyword" }
    }
  }
}

El campo title ahora está mapeado como search_as_you_type con max_shingle_size: 3. Elasticsearch genera automáticamente title._2gram, title._3gram, y title._index_prefix como subcampos internos. No necesitas definirlos manualmente.

El valor predeterminado de 3 es el adecuado para la mayoría de los títulos de contenido. Configurar max_shingle_size: 4 permite una coincidencia de frases de cuatro palabras más precisa, a costa de un índice más grande. Quédate con 3 a menos que tus títulos tengan frecuentemente 5 o más palabras y las frases de 4 palabras no coincidan cuando deberían.

Los campos body y excerpt permanecen como text porque la búsqueda de texto completo opera sobre ellos. El autocompletado solo apunta a title, que es el valor predeterminado correcto para la navegación de contenido. Sugerir fragmentos de frases del cuerpo produce sugerencias incompletas y fuera de contexto. Sugerir fragmentos de títulos ofrece a los usuarios destinos reconocibles al instante.

Verificación del mapeo

Tras crear el índice, verifica el mapeo antes de continuar:

GET /webflow-content-v2/_mapping

La respuesta debería mostrar title con "type": "search_as_you_type" y los tres subcampos internos listados debajo. Si title todavía muestra "type": "text", la solicitud PUT no se aplicó o estás consultando el nombre de índice incorrecto. Corrige el mapeo antes de ejecutar el paso 2.

2. Reindexa tu contenido de Webflow CMS en el nuevo índice

Con el nuevo índice listo, vuelve a ejecutar el script de indexación contra webflow-content-v2. Si seguiste la guía de búsqueda de texto completo, tu script se encuentra en scripts/index-webflow-content.ts.

La versión a continuación actualiza el destino del índice y añade el campo excerpt , que se traslada a las sugerencias de autocompletado en el paso 4.

// scripts/index-webflow-content.ts
// Run with: npx tsx scripts/index-webflow-content.ts

const WEBFLOW_TOKEN     = process.env.WEBFLOW_API_TOKEN!
const COLLECTION_ID     = process.env.WEBFLOW_COLLECTION_ID!
const ELASTIC_URL       = process.env.ELASTIC_URL!
const ELASTIC_WRITE_KEY = process.env.ELASTIC_WRITE_API_KEY!
const INDEX             = 'webflow-content-v2'

interface WebflowItem {
  id: string
  lastPublished: string
  fieldData: {
    name:        string
    slug:        string
    'post-body'?: string
    excerpt?:    string
    category?:   string
    tags?:       string[]
  }
}

async function fetchAllItems(): Promise<WebflowItem[]> {
  const items: WebflowItem[] = []
  let offset = 0

  while (true) {
    const res = await fetch(
      `https://api.webflow.com/v2/collections/${COLLECTION_ID}/items?offset=${offset}&limit=100`,
      { headers: { Authorization: `Bearer ${WEBFLOW_TOKEN}` } }
    )
    const data = await res.json() as {
      items:      WebflowItem[]
      pagination: { total: number }
    }
    items.push(...data.items)
    if (items.length >= data.pagination.total) break
    offset += 100
  }

  return items
}

async function bulkIndex(items: WebflowItem[]): Promise<void> {
  const ndjson =
    items
      .flatMap((item) => [
        JSON.stringify({ index: { _index: INDEX, _id: item.id } }),
        JSON.stringify({
          title:           item.fieldData.name,
          slug:            item.fieldData.slug,
          body:            item.fieldData['post-body'] ?? '',
          excerpt:         item.fieldData.excerpt ?? '',
          category:        item.fieldData.category ?? '',
          tags:            item.fieldData.tags ?? [],
          published_at:    item.lastPublished,
          webflow_item_id: item.id,
        }),
      ])
      .join('\n') + '\n'

  const res = await fetch(`${ELASTIC_URL}/_bulk`, {
    method:  'POST',
    headers: {
      Authorization:  `ApiKey ${ELASTIC_WRITE_KEY}`,
      'Content-Type': 'application/x-ndjson',
    },
    body: ndjson,
  })

  const result = await res.json() as {
    items: Array<{ index?: { error?: unknown } }>
  }
  const indexed = result.items.length
  const errors  = result.items.filter((i) => i.index?.error).length
  console.log(`Indexed ${indexed} items into ${INDEX}. Errors: ${errors}`)
  if (errors > 0) {
    console.error('First error:',
      result.items.find((i) => i.index?.error)?.index?.error)
  }
}

const items = await fetchAllItems()
console.log(`Fetched ${items.length} items from Webflow CMS`)
await bulkIndex(items)

Ejecuta el script desde la raíz de tu proyecto tras confirmar que todas las variables requeridas están configuradas en .env.local:

npx tsx scripts/index-webflow-content.ts

La API bulk requiere Content-Type: application/x-ndjson, no application/json estándar. Cada cuerpo de solicitud alterna entre una línea de acción y una línea de documento, con un salto de línea obligatorio al final del último documento.

El + '\n' al final de la llamada .join('\n') se encarga de esto. Si falta ese salto de línea, se produce un error de análisis silencioso donde el último documento de cada lote se descarta sin que aparezca ningún error evidente en la respuesta.

Una vez que el script termine, verifica que el índice contenga información:

GET /webflow-content-v2/_count

El recuento debería coincidir con el tamaño de tu colección de Webflow CMS. Un recuento de cero sin errores en el script suele significar que el campo _id estaba undefined en cada documento, lo que omite la acción de indexación sin fallar. Registra item.id en fetchAllItems() para confirmar que tus elementos de Webflow tienen IDs válidos antes de volver a ejecutarlo.

3. Crea el manejador de rutas de autocompletado en Webflow Cloud

Crea app/api/autocomplete/route.ts. Esto vive junto al manejador de búsqueda de texto completo en app/api/search/route.ts, pero de forma independiente.

Los mantengo separados en cada proyecto porque gestionan interacciones fundamentalmente distintas: el autocompletado se activa con cada pulsación de tecla (con debounce) y devuelve una lista pequeña y rápida de títulos; la búsqueda de texto completo se activa al enviar el formulario y devuelve resultados paginados con resaltados y facetas.

Fusionarlos crea un controlador más difícil de ajustar, más complicado de limitar en su tasa de peticiones y más difícil de depurar cuando algo falla en un comportamiento pero no en el otro.

// app/api/autocomplete/route.ts
import { NextResponse, type NextRequest } from 'next/server'

const ELASTIC_URL     = process.env.ELASTIC_URL!
const ELASTIC_API_KEY = process.env.ELASTIC_API_KEY!
const INDEX           = process.env.ELASTIC_INDEX ?? 'webflow-content-v2'

interface ElasticHit {
  _source: {
    title:    string
    slug:     string
    excerpt?: string
  }
}

interface ElasticResponse {
  hits: {
    total: { value: number }
    hits:  ElasticHit[]
  }
}

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url)
  const q = searchParams.get('q')?.trim() ?? ''

  if (q.length < 2) {
    return NextResponse.json({ suggestions: [] })
  }

  const esQuery = {
    size:    8,
    _source: ['title', 'slug', 'excerpt'],
    query: {
      multi_match: {
        query:  q,
        type:   'bool_prefix',
        fields: [
          'title',
          'title._2gram',
          'title._3gram',
        ],
      },
    },
  }

  const esRes = await fetch(`${ELASTIC_URL}/${INDEX}/_search`, {
    method:  'POST',
    headers: {
      Authorization:  `ApiKey ${ELASTIC_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(esQuery),
  })

  if (!esRes.ok) {
    const errorText = await esRes.text()
    console.error('Autocomplete Elasticsearch error:', errorText)
    return NextResponse.json(
      { error: 'Autocomplete unavailable' },
      { status: 502 }
    )
  }

  const data = (await esRes.json()) as ElasticResponse

  const suggestions = data.hits.hits.map((hit) => ({
    title:   hit._source.title,
    slug:    hit._source.slug,
    excerpt: hit._source.excerpt ?? null,
  }))

  return NextResponse.json({ suggestions })
}

El tipo de consulta query es el patrón recomendado para campos. Analiza cada término en la cadena de búsqueda, excepto el último, utilizando el analizador estándar del campo, y trata el término final como un prefijo.bool_prefixsearch_as_you_type

Una consulta parcial de "webflow ele" coincide con documentos que contienen "webflow" como un token completo y "ele" como prefijo, mostrando títulos como "Guía de Elasticsearch para Webflow" de inmediato. Los subcampos shingle ( , ) otorgan una puntuación más alta a los documentos cuando los términos escritos aparecen juntos en el valor original del campo, mejorando la relevancia de las consultas de varias palabras sin necesidad de configuración adicional._2gram_3gram

El límite evita que el menú desplegable abrume al usuario. A través del uso en producción en sitios de Webflow, he descubierto que siete u ocho sugerencias es el techo práctico. Por debajo de 5, el menú parece vacío para consultas comunes. Por encima de diez, los usuarios dejan de leer la lista y simplemente envían la consulta de todos modos.size: 8

El mínimo de dos caracteres evita que el controlador realice un escaneo casi completo del índice ante entradas de un solo carácter. Una consulta de "w" en un blog de 500 publicaciones devuelve ocho documentos esencialmente aleatorios. Una consulta de "we" se reduce lo suficiente como para ser orientativa. Para sitios con mucho contenido y varios miles de elementos CMS, tres caracteres como mínimo es un umbral aún mejor.

4. Configura el menú desplegable de autocompletado en el frontend de Webflow

Añade este script a un bloque de código personalizado en la configuración de la página de Webflow, bajo Footer Code, justo antes de la etiqueta de cierre .</body>

En el lienzo de Webflow, asigna a tu elemento de entrada de búsqueda un atributo personalizado de y al elemento contenedor de sugerencias un atributo personalizado de . Aplica estilos a ambos usando las clases CSS existentes en tu proyecto.data-autocomplete-inputdata-autocomplete-results

(function () {
  const input   = document.querySelector('[data-autocomplete-input]')
  const results = document.querySelector('[data-autocomplete-results]')

  if (!input || !results) return

  let debounceTimer
  let controller

  input.addEventListener('input', function () {
    const q = this.value.trim()
    clearTimeout(debounceTimer)

    if (q.length < 2) {
      results.hidden = true
      results.innerHTML = ''
      return
    }

    debounceTimer = setTimeout(function () {
      fetchSuggestions(q)
    }, 200)
  })

  async function fetchSuggestions(q) {
    if (controller) controller.abort()
    controller = new AbortController()

    try {
      const res = await fetch(
        '/app/api/autocomplete?q=' + encodeURIComponent(q),
        { signal: controller.signal }
      )
      if (!res.ok) return
      const data = await res.json()
      renderSuggestions(data.suggestions)
    } catch (err) {
      if (err.name !== 'AbortError') {
        console.error('Autocomplete fetch error:', err)
      }
    }
  }

  function renderSuggestions(suggestions) {
    if (!suggestions || !suggestions.length) {
      results.hidden = true
      results.innerHTML = ''
      return
    }

    results.innerHTML = suggestions
      .map(function (s) {
        return (
          '<a href="/' + s.slug + '" class="autocomplete-suggestion">' +
            '<span class="autocomplete-title">' + escapeHtml(s.title) + '</span>' +
            (s.excerpt
              ? '<span class="autocomplete-excerpt">' + escapeHtml(s.excerpt) + '</span>'
              : '') +
          '</a>'
        )
      })
      .join('')

    results.hidden = false
  }

  function escapeHtml(str) {
    return String(str)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
  }

  document.addEventListener('click', function (e) {
    if (!input.contains(e.target) && !results.contains(e.target)) {
      results.hidden = true
    }
  })
})()

El es la adición más importante en comparación con una implementación básica de debounce. Cuando un usuario escribe "web" y luego continúa inmediatamente a "webfl", se disparan dos llamadas fetch en intervalos de 200ms.AbortController

Sin un controlador de aborto, ambas respuestas llegan, y si la red entrega la respuesta de "web" después de la de "webfl", los resultados obsoletos de la consulta más corta sobrescriben los correctos. El usuario ve cómo las sugerencias saltan hacia atrás a una consulta anterior y menos específica.

El controlador de aborto cancela la solicitud anterior antes de iniciar una nueva, por lo que solo recibe la respuesta de la consulta más reciente. He encontrado este error exacto de resultados obsoletos en producción con usuarios que escriben rápido, y erosiona rápidamente la credibilidad de la búsqueda.renderSuggestions

El debounce de 200ms es intencionalmente más ajustado que los 300ms que uso en la búsqueda de texto completo. El autocompletado se siente ágil a 200ms; cualquier valor por encima de 250ms empieza a notarse con retraso para los usuarios que escriben rápido.

El entorno de ejecución en el borde (edge runtime) de Webflow Cloud ayuda a mantener este margen ajustado porque los Route Handlers se ejecutan desde ubicaciones de borde de Cloudflare cercanas al usuario, en lugar de desde un único servidor de origen.

La función no es opcional. Los títulos y extractos de las sugerencias provienen de contenido CMS escrito por autores reales, y esos autores ocasionalmente incluyen , , , o en un título o extracto. Sin escapar estos caracteres, rompen la cadena HTML, creando una vulnerabilidad XSS. Esta es una preocupación real en producción, no un caso teórico poco común.escapeHtml<>&"

5. Actualiza tu variable de entorno de Elastic Cloud y despliega

El Route Handler de autocompletado lee las mismas variables de entorno , , y que ya utiliza el controlador de búsqueda de texto completo. El único cambio es actualizar para que apunte a , o como hayas nombrado al nuevo índice en el Paso 1.ELASTIC_URLELASTIC_API_KEYELASTIC_INDEXELASTIC_INDEXwebflow-content-v2

En Webflow Cloud, abre tu proyecto, selecciona el entorno y navega a Environment Variables. Actualiza a nombre del nuevo índice. Confirma que contiene la clave de solo lectura. La clave de escritura ( ) solo debería existir en tu archivo local y nunca debería llegar al entorno desplegado.ELASTIC_INDEXELASTIC_API_KEYELASTIC_WRITE_API_KEY.env.local

Después de actualizar la variable, despliega:

webflow cloud deploy

Una vez completado el despliegue, prueba el endpoint de autocompletado directamente antes de tocar el frontend:

curl "https://your-site.webflow.io/app/api/autocomplete?q=web"

La respuesta debe ser un objeto JSON con una suggestions matriz que contenga hasta ocho elementos, cada uno con title, slug, y opcionalmente excerpt. Una matriz vacía en esta etapa casi siempre significa que ELASTIC_INDEX todavía apunta al índice antiguo, o que el script de reindexación del paso 2 se ejecutó contra un índice con otro nombre. Comprueba ambos antes de investigar cualquier otra cosa.

¿Qué causa que el autocompletado de Elasticsearch falle en Webflow Cloud?

La mayoría de los fallos de autocompletado en Webflow Cloud se deben a cuatro categorías:

  • Un nombre de índice que no coincide entre la variable de entorno y el índice real
  • Se están consultando los subcampos search_as_you_type shingle en un índice donde el title todavía está mapeado como text
  • Sugerencias obsoletas que llegan al frontend porque el AbortController no está estructurado correctamente
  • Errores de CORS cuando el sitio de Webflow y la aplicación de Webflow Cloud residen en orígenes diferentes

Vamos a revisar cada uno.

El endpoint de autocompletado devuelve una matriz de sugerencias vacía

Una matriz suggestions vacía cuando el índice tiene contenido apunta a una de estas tres causas: la variable de entorno ELASTIC_INDEX todavía hace referencia al índice antiguo que no tiene el mapeo search_as_you_type , la cadena de consulta tiene menos de dos caracteres y el controlador termina antes de tiempo, o el script de reindexación se completó pero escribió los documentos en un índice con un nombre diferente.

El diagnóstico más rápido es consultar Elasticsearch directamente en las herramientas de desarrollo de Kibana:

POST /webflow-content-v2/_search
{
  "size": 3,
  "query": {
    "multi_match": {
      "query": "web",
      "type": "bool_prefix",
      "fields": [
        "title",
        "title._2gram",
        "title._3gram",
        "title._index_prefix"
      ]
    }
  }
}

Si esto devuelve resultados en Kibana pero el manejador de rutas devuelve vacío, la variable de entorno apunta a un índice diferente. Si esto también devuelve vacío en Kibana, ejecuta GET /webflow-content-v2/_mapping y confirma que title.type muestre search_as_you_type.

Si muestra text, elimina el índice, vuelve a crearlo con el mapeo explícito del paso 1 y ejecuta de nuevo el script de indexación.

El manejador de rutas devuelve un error 400 de Elasticsearch

Una respuesta 400 en la consulta de autocompletado casi siempre significa que los subcampos title._2gram, title._3gram, y title._index_prefix no existen en el índice que se está consultando.

Esto sucede cuando title está mapeado como text en lugar de search_as_you_type, lo cual ocurre siempre que Elasticsearch detecta automáticamente el tipo de campo en la primera escritura del documento. El mapeo dinámico de Elasticsearch siempre elige text para contenido de cadena, nunca search_as_you_type.

Los mapeos explícitos definidos antes de la indexación son la única forma de obtener el tipo de campo correcto.

Confirma con GET /webflow-content-v2/_mapping. Si title.type no es search_as_you_type, elimina el índice, vuelve a crearlo con el mapeo PUT del paso 1 y ejecuta de nuevo el script de indexación contra el índice recién creado.

Aparecen sugerencias obsoletas de una consulta anterior antes de las actuales

Si ves sugerencias de una consulta anterior brevemente antes de las correctas, reemplázalas. El AbortController en el paso 4 no está cancelando correctamente las solicitudes en curso. La causa más común es declarar la variable controller dentro de la devolución de llamada setTimeout o dentro del propio fetchSuggestions , en lugar de en el ámbito IIFE exterior.

Cuando una controller se declara localmente, cada pulsación de tecla crea una variable nueva e independiente en lugar de sobrescribir la compartida. La llamada controller.abort() nunca cancela la solicitud correcta porque la variable a la que hace referencia acaba de crearse, no es la que contiene la búsqueda anterior.

La variable controller debe residir en el ámbito del módulo de la IIFE, fuera tanto de la devolución de llamada setTimeout como de fetchSuggestions, de modo que cada nueva llamada sobrescriba la misma referencia compartida y pueda abortar la solicitud anterior. El script del paso 4 la coloca correctamente al principio de la IIFE, antes del detector de eventos.

Errores de CORS al llamar al Route Handler desde un sitio de Webflow independiente

Si tu sitio de Webflow está alojado en un dominio y tu aplicación de Webflow Cloud en otro, la política de mismo origen del navegador bloqueará la búsqueda de autocompletado. La solución consiste en añadir cabeceras CORS al Route Handler.

Añade un controlador OPTIONS para las solicitudes de preflight e incluye Access-Control-Allow-Origin en la respuesta GET:

const CORS_HEADERS = {
  'Access-Control-Allow-Origin':  'https://your-site.webflow.io',
  'Access-Control-Allow-Methods': 'GET, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
} as const

export async function OPTIONS() {
  return new Response(null, { status: 204, headers: CORS_HEADERS })
}

Pasa { headers: CORS_HEADERS } como segundo argumento a NextResponse.json() en las sentencias de retorno del controlador GET. Sustituye el valor de origen por la URL real de tu sitio de Webflow publicado.

Usar Access-Control-Allow-Origin: * es más sencillo, pero permite llamar al endpoint desde cualquier origen de Internet, lo que expone tu capacidad de consulta de Elastic Cloud a cualquiera que descubra la URL.

Amplía la búsqueda de autocompletado en tu aplicación de Webflow Cloud

La configuración de esta guía ofrece una implementación de autocompletado completa y lista para producción: un mapeo de índice search_as_you_type, un Route Handler de Webflow Cloud que utiliza multi_match con bool_prefix, y una entrada de frontend con debounce y control de aborto que muestra sugerencias de títulos a medida que el usuario escribe.

Para la supervisión de errores en tus Route Handlers, añadir el seguimiento de errores de Sentry a una aplicación de Webflow Cloud cubre la captura y visualización de errores desde los Route Handlers de borde. Para ver cómo se aplican el flujo de trabajo de despliegue y los patrones de variables de entorno en un contexto de integración diferente, crear una aplicación serverless con Neon en Webflow Cloud es una referencia útil.

Explora Webflow + Elastic para conocer otros enfoques de integración, opciones de autenticación y el desglose completo de los enfoques de cliente de Elasticsearch compatibles para proyectos de Webflow Cloud.

Preguntas frecuentes

¿Funciona search_as_you_type en el entorno de ejecución Workers de Webflow Cloud?

Sí. El tipo search_as_you_type es una configuración de mapeo en el índice de Elasticsearch, no una biblioteca cliente con dependencias de tiempo de ejecución. Se consulta a través de la API REST HTTP de Elasticsearch utilizando fetch(), que el entorno de ejecución de Cloudflare Workers admite de forma nativa. La consulta multi_match con bool_prefix es un DSL estándar de Elasticsearch que funciona de forma idéntica tanto si se llama desde Node.js, un navegador o un entorno de ejecución Workers: sin SDK, sin parches de compatibilidad y sin errores de tiempo de ejecución.

¿Necesito volver a indexar todo mi contenido para añadir el autocompletado?

Sí, porque cambiar el tipo de un campo de text a search_as_you_type requiere un nuevo índice con el mapeo actualizado. Elasticsearch no permite cambiar el tipo de campo en un índice existente. Para la mayoría de las colecciones del CMS de Webflow, el script de reindexación del paso 2 se completa en menos de un minuto. Para colecciones con varios miles de elementos, la API de reindexación de Elasticsearch puede copiar documentos entre índices en el lado del servidor sin tener que volver a obtenerlos de la API de datos de Webflow, lo cual es más rápido para grandes conjuntos de datos y evita problemas con los límites de tasa de la API.

¿Puedo realizar autocompletado y búsqueda de texto completo desde el mismo endpoint del Route Handler?

Técnicamente sí, pero es mejor diseñar dos endpoints separados. La consulta de autocompletado se dirige a subcampos search_as_you_type con bool_prefix, devuelve ocho resultados sin paginación y se dispara con cada pulsación de tecla con debounce. La consulta de texto completo utiliza fuzziness: AUTO, devuelve resultados paginados con resaltados y facetas, y se dispara al enviar el formulario. Fusionarlos añade ramificaciones condicionales para comportamientos con diferentes formas de consulta, diferentes objetivos de rendimiento y diferentes preocupaciones sobre límites de tasa. Dos controladores, cada uno haciendo una sola cosa de forma limpia, compensan la pequeña duplicación de código.

¿Cómo mantengo actualizadas las sugerencias de autocompletado a medida que cambia el contenido del CMS?

Registra un webhook de Webflow para collection_item_created y collection_item_changed, que apunte a un Route Handler que reindexe el elemento modificado. En el controlador, obtén el elemento del CMS actualizado de la API de datos de Webflow y, a continuación, llama al endpoint de indexación de un solo documento de Elasticsearch PUT /webflow-content-v2/_doc/{webflow_item_id} con los valores de campo actualizados. Esto mantiene el índice al día sin ejecutar el script completo en cada evento de publicación. Para colecciones que se actualizan con frecuencia, este enfoque incremental es la única solución práctica para producción.

¿Cuál es la longitud mínima de consulta para obtener resultados de autocompletado útiles?

Dos caracteres son el mínimo práctico para obtener sugerencias útiles en la mayoría de los sitios de Webflow. Un solo carácter devuelve demasiadas coincidencias irrelevantes y, en el plan gratuito de Elastic Cloud, escanear todo el índice para un prefijo de una letra genera una latencia notable. Dos caracteres ofrecen resultados lo suficientemente orientativos. Para sitios con mucho contenido y más de 5000 elementos CMS, tres caracteres es un umbral más adecuado. Este mínimo se aplica tanto en el Route Handler como en el script del frontend, evitando así solicitudes que arrojen resultados confusos.

¿Puedo añadir un filtro por categoría al menú desplegable de autocompletado?

Sí. Añade un parámetro de consulta al Route Handler y luego envuelve el existente dentro de una consulta con una cláusula usando una consulta en el campo de palabra clave . El filtro limita las sugerencias a los documentos que coinciden con esa categoría, sin afectar la puntuación de relevancia de las coincidencias en el título. Esto sigue el mismo patrón que el Route Handler de búsqueda de texto completo en la guía complementaria, donde los filtros se ubican dentro de un junto al principal en .categorymulti_matchboolfiltertermcategorytermbool.filtermulti_matchbool.must


Última actualización
July 26, 2026
Categoría

Artículos relacionados

Cómo transmitir cambios de Postgres en vivo a un panel de Webflow Cloud con Supabase
Cómo transmitir cambios de Postgres en vivo a un panel de Webflow Cloud con Supabase

Cómo transmitir cambios de Postgres en vivo a un panel de Webflow Cloud con Supabase

Cómo transmitir cambios de Postgres en vivo a un panel de Webflow Cloud con Supabase

Desarrollo
Por
Colin Lateano
,
,
Leer artículo
Cómo añadir control de acceso basado en roles de Auth0 a una Webflow Cloud App
Cómo añadir control de acceso basado en roles de Auth0 a una Webflow Cloud App

Cómo añadir control de acceso basado en roles de Auth0 a una Webflow Cloud App

Cómo añadir control de acceso basado en roles de Auth0 a una Webflow Cloud App

Guías
Por
Ismail Ajagbe
,
,
Leer artículo
Cómo integrar cursos online de Kajabi con Webflow Cloud usando la API pública
Cómo integrar cursos online de Kajabi con Webflow Cloud usando la API pública

Cómo integrar cursos online de Kajabi con Webflow Cloud usando la API pública

Cómo integrar cursos online de Kajabi con Webflow Cloud usando la API pública

Guías
Por
Ismail Ajagbe
,
,
Leer artículo
Cómo crear un formulario de contacto con envío de correos mediante SendGrid en Webflow Cloud
Cómo crear un formulario de contacto con envío de correos mediante SendGrid en Webflow Cloud

Cómo crear un formulario de contacto con envío de correos mediante SendGrid en Webflow Cloud

Cómo crear un formulario de contacto con envío de correos mediante SendGrid en Webflow Cloud

Guías
Por
Ismail Ajagbe
,
,
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.