Elasticsearch Connector
Elastic Stack
This connector will talk to the Elasticsearch instance directly from the browser.
We strongly recommend proxying requests through your backend using ApiProxyConnector
to avoid exposing API credentials or allowing unrestricted access.
See Using in Production for best practices.
Search UI provides a way to connect to Elasticsearch directly without needing Enterprise Search. This is useful for when you dont need the features of Enterprise Search, such as relevance tuning.
The connector uses the same Search UI configuration that other connectors use.
You must specify either the cloud id or on-premise host url for the Elasticsearch connector.
import ElasticsearchAPIConnector from "@elastic/search-ui-elasticsearch-connector";
import type { IApiClientTransporter } from "@elastic/search-ui-elasticsearch-connector";
class CustomApiClientTransporter implements IApiClientTransporter {
performRequest(searchRequest) {
// Custom implementation
return response;
}
}
const customApiClient = new CustomApiClientTransporter();
const connector = new ElasticsearchAPIConnector({
// Either specify the cloud id or host or apiClient to connect to elasticsearch
cloud: {
id: "<elastic-cloud-id>"
},
host: "http://localhost:9200",
index: "<index-name>",
apiKey: "<api-key>",
// This key will be visible to everyone so ensure its setup with restricted privileges.
// See Authentication section for more details.
connectionOptions: {
// Optional connection options.
headers: {
"x-custom-header": "value"
}
},
// Optional. Custom API client implementation.
// If not provided, a default ApiClientTransporter will be used.
// This allows you to customize how requests are made to Elasticsearch.
apiClient: customApiClient
});
- cloud id found under your cloud deployment overview page
- host url for the Elasticsearch instance
- index name where the search documents are contained
- Optional. apiKey used to authorize a connection to Elasticsearch instance.
- Optional. Specify custom headers to send with the request
Constructor Parameters
Argument | Type | Description |
---|---|---|
config | object | Elasticsearch connection and modification options (see table below). |
Config
Param | Type | Description |
---|---|---|
cloud | object | Required if host or custom apiClient not provided. Object type. The cloud id for the deployment within elastic cloud. Format: { id: 'cloud:id' } . You can find your cloud id in the Elastic Cloud deployment overview page. |
host | string | Required if cloud or custom apiClient not provided. String type. The host url to the Elasticsearch instance |
index | string | Required. String type. The search index name |
apiKey | string | Optional. a credential used to access the Elasticsearch instance. See Connection & Authentication |
connectionOptions | object | Optional. Object containing headers dictionary of header name to header value. |
apiClient | object | Optional. Custom API client implementation. If not provided, a default ApiClientTransporter will be used. This allows you to customize how requests are made to Elasticsearch. The object must implement the IApiClientTransporter interface with a performRequest method that takes a search request and returns a promise with the response. |
interceptSearchRequest | function | Optional. Hook to intercept and modify search requests before they are sent. See Request Lifecycle Hooks for details. |
interceptAutocompleteResultsRequest | function | Optional. Hook to intercept and modify autocomplete results requests before they are sent. See Request Lifecycle Hooks for details. |
interceptAutocompleteSuggestionsRequest | function | Optional. Hook to intercept and modify autocomplete suggestions requests before they are sent. See Request Lifecycle Hooks for details. |
getQueryFn | function | Optional. Function to completely override query generation. See Custom Query Builder for details. |
The connector provides hooks to intercept and modify requests at different stages of the search lifecycle. Each hook has the following type signature:
type SearchQueryHook<T> = (
params: {
requestBody: SearchRequest;
requestState: RequestState;
queryConfig: T;
},
next: (newQueryOptions: SearchRequest) => Promise<ResponseBody>
) => Promise<ResponseBody>;
Where:
RequestState
contains the current search ui state (RequestState)queryConfig
is either QueryConfig for search requests or AutocompleteQueryConfig for autocomplete requestsSearchRequest
is the Elasticsearch request body (Search API Request)ResponseBody
is the Elasticsearch response (Search API Response)
The hooks can be configured in the connector config options:
const connector = new ElasticsearchAPIConnector({
// ... other config options ...
interceptSearchRequest: async (
{ requestBody, requestState, queryConfig },
next
) => {
console.log("Search request:", requestBody);
const response = await next(requestBody);
console.log("Search response:", response);
return response;
},
interceptAutocompleteResultsRequest: async (
{ requestBody, requestState, queryConfig },
next
) => {
console.log("Autocomplete results request:", requestBody);
const response = await next(requestBody);
console.log("Autocomplete results response:", response);
return response;
},
interceptAutocompleteSuggestionsRequest: async (
{ requestBody, requestState, queryConfig },
next
) => {
console.log("Autocomplete suggestions request:", requestBody);
const response = await next(requestBody);
console.log("Autocomplete suggestions response:", response);
return response;
}
});
Each hook must call next(requestBody)
with the request body and return its result. This is required because:
- The
next
function is responsible for actually sending the request to Elasticsearch - Without calling
next
, the request will never reach Elasticsearch - The response from
next
contains the search results that need to be returned to the UI
You can modify the request body before passing it to next
, but you must always call next
and return its result.
These hooks can be used for:
- Request/response logging
- Injecting custom fields
- Dynamically modifying requests based on state
- A/B testing and fallbacks (e.g., KNN fallback)
You can completely customize the query generation using the getQueryFn
hook. The hook is called only when there is a search query, so you don't need to handle empty search terms. The hook has the following type signature:
type GetQueryFn = (
state: RequestState,
queryConfig: QueryConfig
) => SearchRequest["query"];
Where:
RequestState
- RequestState - search UI stateQueryConfig
- QueryConfig - search configurationSearchRequest["query"]
- Query DSL - query part of the Elasticsearch request body
Example usage:
const connector = new ElasticsearchAPIConnector({
// ... other config options ...
getQueryFn: (state, config) => ({
semantic: {
field: "inference_field",
query: state.searchTerm
}
})
});
const connector = new ElasticsearchAPIConnector({
// ... other config options ...
getQueryFn: (state, config) => ({
knn: {
field: "embedding",
query_vector: [
/* embedding array */
],
k: 10,
num_candidates: 100
}
})
});
const connector = new ElasticsearchAPIConnector({
// ... other config options ...
getQueryFn: (state, config) => ({
sparse_vector: {
field: "description_semantic",
inference_id: ".elser-2-elasticsearch",
query: state.searchTerm
}
})
});
const connector = new ElasticsearchAPIConnector({
// ... other config options ...
getQueryFn: (state, config) => ({
multi_match: {
query: state.searchTerm,
fields: ["title^3", "description"],
type: "best_fields",
fuzziness: "AUTO"
}
})
});
The getQueryFn
allows you to:
- Override the default query generation logic
- Implement custom multi_match, match, term and other DSL queries
- Use semantic search, KNN and text_expansion queries for AI-powered search
This hook only replaces the query part of the request body. Filters are still added separately and automatically mixed in.
The ApiProxyConnector
is used when you want to proxy search requests through your own backend rather than exposing your Elasticsearch cluster directly to the browser.
It sends onSearch
and onAutocomplete
requests to your API, which is expected to forward them to Elasticsearch using ElasticsearchAPIConnector
.
import { ApiProxyConnector } from "@elastic/search-ui-elasticsearch-connector/api-proxy";
// Alternatively:
// import { ApiProxyConnector } from "@elastic/search-ui-elasticsearch-connector";
const connector = new ApiProxyConnector({
basePath: "/api",
fetchOptions: {
headers: {
Authorization: "Bearer your-auth-token"
}
}
});
- Base path for your proxy server
- Optional fetch params
Constructor Parameters
Argument | Type | Description |
---|---|---|
basePath | string | Optional. The base URL path for your proxy server. Default is "/api". |
fetchOptions | object | Optional. Custom RequestInit options passed to fetch, e.g., headers or mode. |
Expected Server API
The server is expected to expose two endpoints:
POST /search
— handles search requestsPOST /autocomplete
— handles autocomplete requests
Both endpoints should accept a body with the following format:
{
"state": {
/* RequestState */
},
"queryConfig": {
/* QueryConfig */
}
}
And respond with the standard Search UI response types:
ResponseState
for/search
AutocompleteResponseState
for/autocomplete
For a full working example with server setup, see the Using in Production guide or jump to the CodeSandbox.
{
visitors: {
type: "range",
ranges: [
{ from: 0, to: 10000, name: "0 - 10000" },
{ from: 10001, to: 100000, name: "10001 - 100000" },
{ from: 100001, to: 500000, name: "100001 - 500000" },
{ from: 500001, to: 1000000, name: "500001 - 1000000" },
{ from: 1000001, to: 5000000, name: "1000001 - 5000000" },
{ from: 5000001, to: 10000000, name: "5000001 - 10000000" },
{ from: 10000001, name: "10000001+" }
]
}
}
setFilter("visitors", {
name: "10001 - 100000",
from: 10001,
to: 100000
});
- name of the option
- both from and to will be ignored
If the field isn't a facet, you will be able to apply filters to the search using value
, numeric range
and date range
, depending on the field type.
setFilter("precio", {
name: "precio",
from: rangePrices[0],
to: rangePrices[1]
});
You can use the none
filter type to exclude documents that match certain values (works as a must_not filter in Elasticsearch).
searchQuery: {
filters: [
{
type: "none", // Exclude documents where brand.keyword is "apple"
field: "brand.keyword",
values: ["apple"]
}
];
}
This filter will exclude all documents where the field brand.keyword
is equal to "apple"
.
Search UI supports autocomplete functionality to suggest search terms that provide results. The autocomplete functionality is built on top of the Elasticsearch suggest
and bool prefix query
API.
To take advantage of the feature, first update the autocomplete query configuration.
Below is an example of what the autocompleteQuery
may look like.
autocompleteQuery: {
// performs a prefix search on the query
results: {
resultsPerPage: 5,
search_fields: {
// the fields to prefix search on
title_suggest: {}
},
result_fields: {
// Add snippet highlighting within autocomplete suggestions
title: { snippet: { size: 100, fallback: true }},
nps_link: { raw: {} }
}
},
// performs a query to suggest for values that partially match the incomplete query
suggestions: {
types: {
// Limit query to only suggest based on "title" field
documents: { fields: ["title_completion"] }
},
// Limit the number of suggestions returned from the server
size: 4
}
}
- number of results to display. Default is 5.
Above we are configuring both the results
and suggestions
sections of the autocomplete query.
results
will need a search field to perform a prefix search on the query. We advise using a search_as_you_type
field to be used. suggestions
require a completion
type field to perform a query to suggest for values that partially match the incomplete query.
Below is an example of the mappings for the above example. title_suggest
is a search_as_you_type
field and title_completion
is a completion
type field.
{
"mappings": {
"properties": {
"title_suggest": {
"type": "search_as_you_type"
},
"title_completion": {
"type": "completion"
}
}
}
}
With a combination of this configuration + the Searchbox component with autocomplete configuration, your users will be able to see suggestions as they type within the search box.
The Elasticsearch Connector supports typo tolerance through Elasticsearch's fuzziness
setting. This is enabled by setting fuzziness: true
in the searchQuery
configuration (or in autocomplete
query configurations that follow the same structure).
When enabled, fuzziness: true
is internally translated to fuzziness: "AUTO"
in Elasticsearch multi_match
queries. The AUTO
mode automatically adjusts the allowed edit distance based on the length of the search term, enabling effective fuzzy matching for both short and long inputs.
For more details, refer to the Elasticsearch Fuzzy Query documentation.