Skip to content

InstantSearch

POST /:handle/instantsearch

The InstantSearch endpoint accepts Algolia’s multi-query format, so InstantSearch.js widgets work out of the box with a small custom search client.

Supported widgets: SearchBox, Hits, Highlight, Pagination, HitsPerPage, RefinementList, CurrentRefinements, ClearRefinements, Stats, Configure.

Create a search client that points at your Search API instance instead of Algolia:

function createSearchClient(endpoint, index, token) {
return {
search(requests) {
const headers = { "Content-Type": "application/json" };
if (token) headers.Authorization = `Bearer ${token}`;
return fetch(`${endpoint}/${index}/instantsearch`, {
method: "POST",
headers,
body: JSON.stringify({ requests }),
}).then((res) => res.json());
},
};
}

Then pass it to <InstantSearch>:

import {
ClearRefinements, CurrentRefinements, Hits, HitsPerPage,
InstantSearch, Pagination, RefinementList, SearchBox, Stats,
} from "react-instantsearch";
const searchClient = createSearchClient("http://localhost:3000", "my_index");
function App() {
return (
<InstantSearch searchClient={searchClient} indexName="my_index">
<SearchBox />
<Stats />
<HitsPerPage items={[
{ label: "10 per page", value: 10 },
{ label: "20 per page", value: 20, default: true },
]} />
<CurrentRefinements />
<ClearRefinements />
<RefinementList attribute="category" />
<Hits />
<Pagination />
</InstantSearch>
);
}

The same approach works with Vue InstantSearch and Angular InstantSearch — only the searchClient factory is needed.

The endpoint expects a JSON body with a requests array. Each request corresponds to one widget query:

{
"requests": [
{
"indexName": "my_index",
"query": "castle",
"params": {
"page": 0,
"hitsPerPage": 20,
"facets": ["category"],
"facetFilters": [["category:Historic", "category:Castle"], "country:Scotland"],
"highlightPreTag": "<em>",
"highlightPostTag": "</em>"
}
}
]
}
ParameterTypeDefaultDescription
querystring""Search query text.
pagenumber0Page number (0-indexed, as Algolia expects).
hitsPerPagenumber20Results per page.
facetsstring[]Fields to aggregate. ["*"] falls back to config defaults.
facetFilters(string|string[])[]Facet filters. Outer = AND, inner array = OR. Format: "field:value".
numericFiltersstring[]Numeric range filters. Format: "field>=10", "field<=100".
attributesToRetrievestring[]all fieldsFields to return in each hit.
highlightPreTagstring<em>Opening tag for highlights.
highlightPostTagstring</em>Closing tag for highlights.

Each result in the response array follows the Algolia format:

{
"results": [
{
"hits": [
{
"objectID": "498",
"title": "Stirling Castle",
"_highlightResult": {
"title": {
"value": "Stirling <em>Castle</em>",
"matchLevel": "full"
}
}
}
],
"nbHits": 42,
"nbPages": 3,
"page": 0,
"hitsPerPage": 20,
"facets": {
"category": { "Historic": 18, "Castle": 12 }
},
"processingTimeMS": 5,
"query": "castle",
"exhaustiveNbHits": true
}
]
}
FieldTypeDescription
hitsobject[]Matching documents with highlights.
nbHitsnumberTotal matching documents.
nbPagesnumberTotal pages.
pagenumberCurrent page (0-indexed).
hitsPerPagenumberResults per page.
facetsRecord<string, Record<string, number>>Facet counts in Algolia format.
processingTimeMSnumberServer-side processing time.
querystringEchoed query string.
exhaustiveNbHitsbooleanAlways true.

The endpoint translates between InstantSearch conventions and Search API internals:

  • Page numbering: 0-indexed (Algolia) ↔ 1-indexed (Search API)
  • Facets: {field: {value: count}} (Algolia) ↔ {field: [{value, count}]} (Search API)
  • Highlights: <em> tags with matchLevel (Algolia) ↔ <mark> tags in arrays (Search API)
  • Filters: facetFilters array syntax ↔ filters object syntax
  • Field aliases: Applied automatically when configured — aliases work in facets, filters, and highlight keys

Config-level boosts, searchableFields, and default facets are applied automatically.

StatusCondition
401Missing or invalid bearer token
404Index handle not found
422Invalid request body