> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conditional requests with InstantSearch.js

> Learn how to make conditional requests with InstantSearch.js

export const SearchRequest = () => <Tooltip tip="A search request is a single HTTP call to the Algolia Search API that can run one or more search operations. It can include multiple queries, for example, when querying several indices at once.">
    search request
  </Tooltip>;

export const SearchQuery = () => <Tooltip tip="The text users enter into a search box. In the Search API, this corresponds to the query parameter. A search query is often used with filters, facets, and other parameters, but these aren't part of the query text itself.">
    search query
  </Tooltip>;

By default, InstantSearch sends an initial <SearchRequest /> to Algolia's servers with an empty <SearchQuery />.
This connection helps speed up later requests.

However, sometimes you don't want to perform more network calls than are necessary.
For example, you may want to limit the number of search requests and reduce your overall Algolia usage.
This guide helps you build a UI that prevents this initial request.

## How a search client works

InstantSearch is the UI layer that sits on top of [Algolia's search client layer](https://github.com/algolia/algoliasearch-client-javascript),
with a state managed by the [Algolia search helper](/doc/guides/building-search-ui/upgrade-guides/js#algolia-search-helper) layer.
These three layers are interchangeable so that you can use the InstantSearch widgets with a different search client.

The search client queries Algolia's servers whenever users refines a search.
You can build a custom search client to add custom behavior.

For example,
to perform [backend searches with InstantSearch](/doc/guides/building-search-ui/going-further/backend-search/in-depth/backend-instantsearch/js).

## Implementing a proxy

To prevent the initial empty query, you must wrap a custom search client around Algolia's, and pass it to [`instantsearch`](/doc/api-reference/widgets/instantsearch/js). The custom search client acts as a proxy for search requests:

<Note>
  All examples in this guide assume you've included InstantSearch.js in your web page from a CDN. If, instead, you're using it with a package manager, adjust how you [import InstantSearch.js and its widgets](/doc/guides/building-search-ui/installation/js) for more information.
</Note>

```js JavaScript theme={"system"}
const algoliaClient = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "ALGOLIA_SEARCH_API_KEY",
);

const searchClient = {
  ...algoliaClient,
  search(requests) {
    return algoliaClient.search(requests);
  },
};

const search = instantsearch({
  indexName: "instant_search",
  searchClient,
});

search.addWidgets([
  instantsearch.widgets.searchBox({
    container: "#searchbox",
  }),

  instantsearch.widgets.hits({
    container: "#hits",
  }),
]);

search.start();
```

This proxy lets you add some logic before calling the `search` method. In this case, you only call it when performing a query.

<Note>
  You can also use a proxy to only begin searching after a certain number of characters have been typed by adding a condition, for example, `query.length > 3`.
</Note>

## Detecting empty search requests

If you don't want to perform a search request when the query is empty (`""`),
you need to detect it:

```js JavaScript icon=code theme={"system"}
const searchClient = {
  ...algoliaClient,
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      // Here we have to do something else
    }

    return algoliaClient.search(requests);
  },
};
```

<Note>
  Sometimes, one user action results in multiple queries, for example, clicking on an [`refinementList`](/doc/api-reference/widgets/refinement-list/js) or using multiple [`index`](/doc/api-reference/widgets/index-widget/js) widgets. Make sure that every query is empty before intercepting the function call.
</Note>

When an empty search is detected, you must return a [formatted response](/doc/libraries/sdk/v1/methods/search#response) as an array of objects of the same length as the `requests` array. Each object requires at least these properties: `hits`, `nbHits`, and `processingTimeMS`.

```js JavaScript icon=code theme={"system"}
const searchClient = {
  ...algoliaClient,
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      return Promise.resolve({
        results: requests.map(() => ({
          hits: [],
          nbHits: 0,
          nbPages: 0,
          page: 0,
          processingTimeMS: 0,
          hitsPerPage: 0,
          exhaustiveNbHits: false,
          query: "",
          params: "",
        })),
      });
    }

    return algoliaClient.search(requests);
  },
};
```

Now you can use the proxy with the [`instantsearch`](/doc/api-reference/widgets/instantsearch/js) widget, like this:

```js JavaScript theme={"system"}
const algoliaClient = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "ALGOLIA_SEARCH_API_KEY",
);

const searchClient = {
  ...algoliaClient,
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      return Promise.resolve({
        results: requests.map(() => ({
          hits: [],
          nbHits: 0,
          nbPages: 0,
          page: 0,
          processingTimeMS: 0,
          hitsPerPage: 0,
          exhaustiveNbHits: false,
          query: "",
          params: "",
        })),
      });
    }

    return algoliaClient.search(requests);
  },
};

const search = instantsearch({
  indexName: "instant_search",
  searchClient,
});

search.addWidgets([
  instantsearch.widgets.searchBox({
    container: "#searchbox",
  }),

  instantsearch.widgets.hits({
    container: "#hits",
  }),
]);

search.start();
```
