Instalar Search en una storefront headless
Esta página instala Search en una storefront que no es un theme de Shopify: un front headless, un sitio custom o cualquier stack cuyo frontend escribes tú. En un theme de Shopify, sigue mejor Instalar Search en Shopify.
Search es una búsqueda por palabras clave en tu catálogo de Dialog: compara las palabras de la consulta con tus productos, con tolerancia a errores de escritura, sinónimos y productos fijados. Tienes tres formas de conectarla, de la más lista para usar a la más libre:
| Opción | Úsala cuando |
|---|---|
| Componentes de React o Vue | Tu storefront funciona con React o Vue 3: una barra de búsqueda y un panel de resultados, listos para integrar. |
| Search controller del SDK | Cualquier otro framework o JS vanilla: el SDK ejecuta la búsqueda, tú pintas los resultados. |
| API REST | Llamas a Search desde tu propio servidor o cliente, sin el SDK. |
Antes de empezar
Sección titulada «Antes de empezar»- Tu API key pública: todas las opciones se autentican con la API key pública de Dialog. Consulta Dónde encontrar tus API keys. Nunca uses la key privada en una storefront.
- Tu catálogo en Dialog: Search devuelve los productos de tu catálogo de Dialog. Comprueba primero que está sincronizado (Integración del catálogo).
- Un idioma y una divisa: un código de idioma ISO 639-1 (
es) y una divisa ISO 4217 (EUR). Search mantiene un índice por idioma y divisa; un locale regional comoes-ESse rechaza como idioma.
Componentes de React o Vue
Sección titulada «Componentes de React o Vue»@askdialog/dialog-react y @askdialog/dialog-vue incluyen una barra de búsqueda (DialogSearchBar) y un panel de resultados (DialogSearchResults) sobre el search controller del SDK: useDialogSearch({ client, language, currency }) crea el controller, los dos componentes lo pintan. El panel muestra los productos (y las colecciones, si las pides), resalta la coincidencia con la consulta en cada título y pagina.
El ejemplo de código y la referencia completa del hook y de los componentes (opciones, props, adaptador de router, columna de colecciones) están con cada paquete:
Search controller del SDK
Sección titulada «Search controller del SDK»Fuera de React y Vue, usa createSearchController de @askdialog/dialog-sdk. El controller envía las peticiones y mantiene el estado de la búsqueda; tú pintas los resultados a partir de ese estado.
import { createSearchController, Dialog } from '@askdialog/dialog-sdk'
const client = new Dialog({ apiKey: 'YOUR_PUBLIC_API_KEY', locale: 'es-ES', currency: 'EUR' })
const controller = createSearchController({ search: (request, options) => client.search(request, options), language: 'es', currency: client.currency, analytics: { surface: 'search_page', trackViewSearchResults: (params) => client.trackViewSearchResults(params), trackSelectSearchResult: (params) => client.trackSelectSearchResult(params), },})
controller.subscribe((state) => render(state)) // tu renderizadoinput.oninput = () => controller.setQuery(input.value)La referencia del SDK: createSearchController da el cableado completo (impresiones, clics, paginación), las opciones, los métodos y el estado.
API REST
Sección titulada «API REST»El SDK y los componentes llaman al endpoint POST /public/search/lexical. Llámalo directamente cuando no uses el SDK, por ejemplo desde tu propio servidor.
POST https://api.askdialog.ai/public/search/lexicalContent-Type: application/jsonx-dialog-api-key: YOUR_PUBLIC_API_KEYAutenticación
Sección titulada «Autenticación»Envía tu API key pública en el header x-dialog-api-key. Una petición sin key, o con una key desconocida, responde 401.
El endpoint tiene un límite por dirección IP: 20 peticiones por segundo. Por encima, responde 429 con un header Retry-After.
Petición
Sección titulada «Petición»El body contiene una entrada por índice a buscar, en requests (de 1 a 10 entradas). Todas las entradas deben compartir la misma query, el mismo idioma y la misma divisa.
{ "requests": [ { "indexName": "products_es_eur", "query": "zapatillas de running", "page": 0, "hitsPerPage": 20 }, { "indexName": "collections_es_eur", "query": "zapatillas de running", "hitsPerPage": 5 } ]}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
indexName |
string |
Sí | <index>_<idioma>_<divisa>. <index> es products, collections, articles o pages; la divisa va en minúsculas (products_es_eur). Pide solo un índice que tenga tu catálogo: uno ausente hace fallar toda la petición. |
query |
string |
Sí | La consulta del comprador: de 2 a 200 caracteres, tras el trim. |
page |
number |
No | Página, empezando en 0. Por defecto 0. |
hitsPerPage |
number |
No | Resultados por página, de 1 a 100. Por defecto 20. |
facetFilters |
array |
No | Filtros por valor, solo en las entradas products. Ver Filtros. |
numericFilters |
array |
No | Filtros numéricos, solo en las entradas products. Ver Filtros. |
Un campo desconocido en el body o en una entrada responde 400.
Filtros
Sección titulada «Filtros»Los filtros acotan una entrada products sobre los atributos filtrables de tu catálogo, los que publicas en Filtros de productos: un filtro sobre otro atributo responde 400. Los dos campos son una lista de grupos: los grupos se combinan con AND, los filtros de un mismo grupo con OR.
{ "indexName": "products_es_eur", "query": "chaqueta", "facetFilters": [[{ "attribute": "color", "value": "negro" }, { "attribute": "color", "value": "marino" }]], "numericFilters": [[{ "attribute": "price", "from": 50, "to": 150 }]]}- Un filtro de faceta es
{ attribute, value, negated? }. Ponnegated: truepara excluir el valor. - Un filtro numérico es
{ attribute, operator, value }, conoperatorentre<,<=,=,!=,>=,>, o un rango{ attribute, from, to }.
Respuesta
Sección titulada «Respuesta»La respuesta contiene un resultado por entrada, en results, en el orden de la petición.
{ "results": [ { "index": "products_es_eur", "hits": [ { "objectID": "product-123", "title": "Zapatillas de trail", "url": "https://mitienda.es/products/zapatillas-de-trail", "handle": "zapatillas-de-trail", "imageUrl": "https://cdn.mitienda.es/trail.jpg", "priceRange": { "min": { "amount": "89.90", "currencyCode": "EUR" }, "max": { "amount": "99.90", "currencyCode": "EUR" } } } ], "nbHits": 42, "page": 0, "nbPages": 3, "hitsPerPage": 20, "processingTimeMS": 12, "query": "zapatillas de running", "queryID": "5f0c..." } ]}Cada resultado:
| Campo | Tipo | Descripción |
|---|---|---|
index |
string |
El indexName de la entrada. |
hits |
array |
Los registros de esta página. |
nbHits |
number |
Número total de coincidencias, todas las páginas incluidas. |
page |
number |
Página devuelta, empezando en 0. |
nbPages |
number |
Número de páginas. |
hitsPerPage |
number |
Tamaño de página aplicado. |
processingTimeMS |
number |
Tiempo de búsqueda, en milisegundos. |
query |
string |
La consulta buscada. |
queryID |
string |
Identificador de esta búsqueda, uno por entrada. |
filters |
array |
Opcional: los filtros aplicados a la entrada, un bloque por fuente. |
Cada hit lleva objectID (el identificador del registro) y, cuando se conocen, sus campos de visualización: title, url, handle, imageUrl y, para los productos, un priceRange (min y max, cada uno con un amount en cadena decimal como "24.90" y un currencyCode opcional).
Los hits de producto también pueden llevar sus datos de compra, todos opcionales:
| Campo | Tipo | Descripción |
|---|---|---|
totalVariants |
number |
Número de variantes. |
tracksInventory |
boolean |
Si el producto controla su stock. |
totalInventory |
number |
Stock sumado de las variantes. |
options |
array |
Opciones del producto: { name, values }. |
variants |
array |
Variantes: id, title, url, imageUrl, price, compareAtPrice, inventoryQuantity, inventoryPolicy, selectedOptions ({ name, value }). |
El stock de una variante no se guarda como booleano: dedúcelo de inventoryQuantity e inventoryPolicy, según el tracksInventory del producto.
Errores
Sección titulada «Errores»| Estado | Causa |
|---|---|
400 |
Body no válido: campo desconocido, consulta de menos de 2 caracteres, entradas con consultas, idiomas o divisas distintos, o filtro sobre un atributo no filtrable. |
401 |
API key pública ausente o desconocida. |
404 |
Nombre de índice inexistente, por ejemplo un nombre mal formado o sin sufijo de divisa (products_es). |
429 |
Límite de peticiones alcanzado: reintenta tras el retardo de Retry-After. |
502, 503, 504 |
Search no está disponible por el momento: reintenta más tarde. |
Los bodies de error llevan un statusCode y un message.
Verifica tu instalación
Sección titulada «Verifica tu instalación»En tu storefront:
- Escribe el nombre de un producto en tu campo de búsqueda: aparecen productos de Dialog.
- Escríbelo con un error: siguen apareciendo los productos correctos.
- Haz clic en un resultado: se abre su página de producto.
- Cambia de página con la paginación: se cargan los resultados siguientes.
Si nunca aparece ningún resultado, revisa tu API key pública y la sincronización de tu catálogo, y luego la pestaña de red: un 404 apunta al nombre del índice, un 401 a la key.
Relacionado
Sección titulada «Relacionado»- Vista general de Search: qué hace Search y las condiciones de la beta.
- Referencia del SDK: Search: opciones, métodos y estado de
client.search()ycreateSearchController. - Componentes React: Búsqueda en la storefront y Componentes Vue: Búsqueda en la storefront.
- Vista general developers: la API, el SDK y los paquetes de componentes.
