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

# Customize the API clients

> Customize your API clients to tailor request logging, timeouts, user agent information, headers, and hosts for flexible integrations.

export const Legacy = ({title, href}) => {
  return <Note>

    This page documents an earlier version of the API client.
    For the latest version, see <a href={href}>{title}</a>.

    </Note>;
};

<Legacy title="Customize the API clients" href="/doc/libraries/sdk/customize" />

To change individual requests made with an API client, see [Request options](/doc/libraries/sdk/v1/request-options).
To change **all** requests,
create a custom configuration.
This lets you change timeouts, HTTP headers, and other settings.

## Custom hosts

You can change the [default hosts](/doc/rest-api/search#base-urls) to which the API client connects:

<CodeGroup>
  ```cs C# theme={"system"}
  SearchConfig config = new SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  {
      CustomHosts = new List<StatefulHost>
      {
          new StatefulHost
          {
              Url = "yourapplication.example.net",
              Up = true,
              LastUse = DateTime.UtcNow,
              Accept = CallType.Read | CallType.Write,
          },
      }
  };

  SearchClient client = new SearchClient(config);
  ```

  ```go Go theme={"system"}
  configuration := search.Configuration{
  	AppID:  "ALGOLIA_APPLICATION_ID",
  	APIKey: "ALGOLIA_API_KEY",
  	Hosts:  []string{"yourapplication.example.net"},
  }

  client := search.NewClientWithConfig(configuration)
  index := client.InitIndex("INDEX_NAME")
  ```

  ```java Java theme={"system"}
  SearchClient client =
      DefaultSearchClient.create(
          new SearchConfig.Builder("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
                  .setHosts(
                      Arrays.asList(
                          new StatefulHost("yourapplication.example.net", EnumSet.of(CallType.READ)),
                          new StatefulHost("yourapplication.example.net", EnumSet.of(CallType.WRITE))))
                  .build());
  ```

  ```js JavaScript theme={"system"}
  // Default version
  import algoliasearch from "algoliasearch";

  // Search-only version
  // import algoliasearch from 'algoliasearch/lite';

  const client = algoliasearch("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", {
    hosts: [{ url: "yourapplication.example.net" }],
  });
  const index = client.initIndex("INDEX_NAME");
  ```

  ```kotlin Kotlin theme={"system"}
  val client =
      ClientSearch(
          ConfigurationSearch(
              applicationID = ApplicationID("ALGOLIA_APPLICATION_ID"),
              apiKey = APIKey("ALGOLIA_API_KEY"),
              hosts = listOf(RetryableHost("yourapplication.example.net"))
          )
      )
  ```

  ```php PHP theme={"system"}
  <?php
  require __DIR__ . '/vendor/autoload.php';

  use Algolia\AlgoliaSearch\SearchClient;
  use Algolia\AlgoliaSearch\Config\SearchConfig;

  $config = [
      'appId' => 'ALGOLIA_APPLICATION_ID',
      'apiKey' => 'ALGOLIA_API_KEY',
      'hosts' => ['yourapplication.example.net']
  ];

  $client = SearchClient::createWithConfig(
      new SearchConfig($config)
  );

  $index = $client->initIndex('INDEX_NAME');
  ```

  ```python Python theme={"system"}
  from algoliasearch.configs import Config
  from algoliasearch.http.hosts import Host, HostsCollection
  from algoliasearch.search_client import SearchClient


  class CustomConfig(Config):
      def build_hosts(self):
          return HostsCollection([Host("yourdomain.com")])


  config = CustomConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  client = SearchClient.create_with_config(config)
  ```

  ```ruby Ruby theme={"system"}
  require "algolia"

  client = Algolia::Search::Client.new(
    Algolia::Search::Config.new(
      {
        application_id: "ALGOLIA_APPLICATION_ID",
        api_key: "ALGOLIA_API_KEY",
        custom_hosts: [
          "yourdomain.com"
        ]
      }
    )
  )
  ```

  ```swift Swift theme={"system"}
  import AlgoliaSearchClient

  let configuration = SearchConfiguration(
    applicationID: "ALGOLIA_APPLICATION_ID",
    apiKey: "ALGOLIA_API_KEY"
  )
    .set(\.hosts, to: [.init(url: URL(string: "yourapplication.example.net")!)])

  let client = SearchClient(configuration: configuration)
  let index = client.index(withName: "INDEX_NAME")
  ```
</CodeGroup>

Changing the hosts can be useful if you want to proxy the search requests through another server, for example,
to process the request or response, or to perform custom analytics.

## Add HTTP headers to every request

Adding HTTP headers to your requests lets you set parameters such as a user identifier or an IP address.
This can be useful for analytics, geographical search, or applying API key rate limits.

<CodeGroup>
  ```cs C# theme={"system"}
  var configuration = new SearchConfig("undefined", "undefined");
  configuration.DefaultHeaders.Add("NAME-OF-HEADER", "value-of-header");

  SearchClient client = new SearchClient(configuration);
  ```

  ```go Go theme={"system"}
  config := search.Configuration{
  	AppID:  "ALGOLIA_APPLICATION_ID",
  	APIKey: "ALGOLIA_API_KEY",
  	Headers: map[string]string{
  		"NAME-OF-HEADER": "value-of-header",
  	},
  }

  client := search.NewClientWithConfig(config)
  ```

  ```java Java theme={"system"}
  SearchConfig configuration = new SearchConfig.Builder("ALGOLIA_APPLICATION_ID",
      "ALGOLIA_API_KEY").addExtraHeaders("NAME-OF-HEADER", "value-of-header").build();

  SearchClient client = DefaultSearchClient.create(configuration);
  ```

  ```js JavaScript theme={"system"}
  const client = algoliasearch("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", {
    headers: {
      "NAME-OF-HEADER": "value-of-header",
    },
    // Also works with query parameters
    queryParameters: {
      "NAME-OF-QUERY-PARAMETER": "value-of-query-parameter",
    },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val configuration = ConfigurationSearch(
      applicationID = ApplicationID("ALGOLIA_APPLICATION_ID"),
      apiKey = APIKey("ALGOLIA_API_KEY"),
      defaultHeaders = mapOf("NAME-OF-HEADER" to "value-of-header")
  )
  ClientSearch(configuration)
  ```

  ```php PHP theme={"system"}
  <?php
  use Algolia\AlgoliaSearch\Config\SearchConfig;
  use Algolia\AlgoliaSearch\SearchClient;

  $config = SearchConfig::create('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY');
  $config->setDefaultHeaders([
    'headerName' => 'headerValue'
  ]);

  $client = SearchClient::createWithConfig($config);
  ```

  ```python Python theme={"system"}
  config = SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  config.headers["NAME-OF-HEADER"] = "value-of-header"

  client = SearchClient.create_with_config(config)
  ```

  ```ruby Ruby theme={"system"}
  config = Algolia::Search::Config.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  config.headers["NAME-OF-HEADER"] = "value-of-header"
  ```

  ```scala Scala theme={"system"}
  val client = new AlgoliaClient(
    "ALGOLIA_APPLICATION_ID",
    "ALGOLIA_API_KEY",
    customHeader = Map(
      "NAME-OF-HEADER" -> "value-of-header"
    )
  )
  ```

  ```swift Swift theme={"system"}
  let configuration = SearchConfiguration(applicationID: "ALGOLIA_APPLICATION_ID", apiKey: "ALGOLIA_API_KEY")
    .set(\.defaultHeaders, to: ["NAME-OF-HEADER": "value-of-header"])

  let client = SearchClient(configuration: configuration)
  ```
</CodeGroup>

You can add these headers to your requests:

<table>
  <thead>
    <tr>
      <th>Header</th>
      <th>Use cases</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code style={{wordBreak: "keep-all"}}>X-Algolia-UserToken</code></td>

      <td>
        * [API key rate limits](/doc/guides/security/api-keys/in-depth/api-key-restrictions#rate-limit)
        * Identifies users for the Analytics API. Overrides `X-Forwarded-For`. Use to forward user identity without relying on IP addresses.
      </td>
    </tr>

    <tr>
      <td><code style={{wordBreak: "keep-all"}}>X-Forwarded-For</code></td>

      <td>
        * For backend analytics, forward the user's IP address. Otherwise, analytics uses your server's IP and treats all users as a single user.
        * For backend location (geo) searches, set to the user's IP to ensure accurate geolocation. Otherwise, the server's IP is used.
      </td>
    </tr>
  </tbody>
</table>

### Add custom headers to individual requests

<CodeGroup>
  ```cs C# theme={"system"}
  Index index = client.InitIndex("INDEX_NAME");

  RequestOptions requestOptions = new RequestOptions
  {
      Headers = new Dictionary<string,string>{ { "X-Algolia-UserToken", "user123" } }
  };

  var result = index.Search<Result>(new Query("query string"), requestOptions);
  ```

  ```go Go theme={"system"}
  opts := []interface{}{
  	opt.ExtraHeaders(map[string]string{
  		"X-Algolia-UserToken": "user123",
  	}),
  }

  res, err := index.Search("query string", opts...)
  ```

  ```java Java theme={"system"}
  SearchIndex<Result> index = client.initIndex("INDEX_NAME", Result.class);
  Query query = new Query("query string");
  RequestOptions requestOptions = new RequestOptions().addExtraHeader("X-Algolia-UserToken",
          "user123");

  // Sync
  SearchResult<Result> search = index.search(query, requestOptions);

  // Async
  CompletableFuture<SearchResult<Result>> search = index.searchAsync(query, requestOptions);
  ```

  ```js JavaScript theme={"system"}
  const index = client.initIndex("INDEX_NAME");

  const requestOptions = {
    headers: { "X-Algolia-UserToken": "user123" },
  };

  index.search("query string", requestOptions).then(({ hits }) => {
    console.log(hits);
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val indexName = IndexName("INDEX_NAME")
  val index = client.initIndex(indexName)
  val query = Query("query string")
  val requestOptions = requestOptions {
      header("X-Algolia-UserToken", "user123")
  }

  index.search(query, requestOptions)
  ```

  ```php PHP theme={"system"}
  <?php
  $index = $client->initIndex('INDEX_NAME');

  $res = $index->search('query string', [
    'X-Algolia-UserToken' => 'user123'
  ]);
  ```

  ```python Python theme={"system"}
  index = client.init_index("INDEX_NAME")

  request_options = {
      "X-Algolia-UserToken": "user123",
  }

  res = index.search("query string", request_options)
  ```

  ```ruby Ruby theme={"system"}
  index = client.init_index("INDEX_NAME")

  request_options = {
    :"X-Algolia-UserToken" => "user123"
  }

  res = index.search("query string", request_options)
  ```

  ```scala Scala theme={"system"}
  client.execute {
    search into "INDEX_NAME" query Query(
        query = Some("query string")
    ) options RequestOptions(
        extraHeaders = Some(Map("X-Algolia-UserToken" -> "user123"))
    )
  }
  ```

  ```swift Swift theme={"system"}
  let index = client.index(withName: "INDEX_NAME")
  var requestOptions = RequestOptions()
  requestOptions.headers["X-Algolia-UserToken"] = "user123"
  index.search(query: "query string", requestOptions: requestOptions) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

The user token should match the [`userToken`](/doc/libraries/search-insights/set-user-token#param-user-token) in events sent to the Insights API (also known as the anonymous user token, or session user token).

## Change timeouts for all requests

Network connections and DNS resolution can be slow.
That's why the API clients come with default timeouts.

<CodeGroup>
  ```cs C# theme={"system"}
  var configuration = new SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  {
    ConnectTimeout = 15, // connection timeout in seconds
    ReadTimeout = 5, // read timeout in seconds
    WriteTimeout = 30, // write timeout in seconds
    HostDownDelay = 300 // delay before retrying a host that was down, in seconds (= 5 minutes)
  };
  ```

  ```go Go theme={"system"}
  config := search.Configuration{
      AppID:          "ALGOLIA_APPLICATION_ID",
      APIKey:         "ALGOLIA_API_KEY",
      ConnectTimeout: 2 * time.Second, // connection timeout in seconds
      ReadTimeout:    5 * time.Second, // read timeout in seconds
      WriteTimeout:   30 * time.Second, // write timeout in seconds
      HostDownDelay:  5 * 60 * time.Second, // delay before retrying a host that was down, in seconds (= 5 minutes)
  }

  client := search.NewClientWithConfig(config)
  ```

  ```java Java theme={"system"}
  SearchConfig configuration = new SearchConfig.Builder("ALGOLIA_APPLICATION_ID",
      "ALGOLIA_API_KEY").setConnectTimeOut(2000) // connection timeout in milliseconds
      .setReadTimeOut(5000) // read timeout in milliseconds
      .setWriteTimeOut(30000) // write timeout in milliseconds
      .setHostDownDelay(300000) // delay before retrying a host we know was down, in milliseconds
      .build();

  SearchClient client = DefaultSearchClient.create(configuration);
  ```

  ```js JavaScript theme={"system"}
  const client = algoliasearch(appId, apiKey, {
    timeouts: {
      connect: 2, // connection timeout in seconds
      read: 5, // read timeout in seconds
      write: 30, // write timeout in seconds
    },
  });

  const analytics = client.initAnalytics({
    timeouts: {
      connect: 2, // connection timeout in seconds
      read: 5, // read timeout in seconds
      write: 30, // write timeout in seconds
    },
  });

  const personalization = client.initPersonalization({
    timeouts: {
      connect: 2, // connection timeout in seconds
      read: 5, // read timeout in seconds
      write: 30, // write timeout in seconds
    },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val configuration = ConfigurationSearch(
      applicationID = ApplicationID("ALGOLIA_APPLICATION_ID"),
      apiKey = APIKey("ALGOLIA_API_KEY"),
      connectTimeout = 2000 // connection timeout in milliseconds
      readTimeout = 5000, // read timeout in milliseconds
      writeTimeout = 30000 // write timeout in milliseconds
  )
  ClientSearch(configuration)
  ```

  ```php PHP theme={"system"}
  <?php
  $config = SearchConfig::create('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY');
  $config->setConnectTimeout(2); // connection timeout in seconds
  $config->setReadTimeout(30); // read timeout in seconds
  $config->setWriteTimeout(30); // write timeout in seconds

  SearchClient::createWithConfig($config);
  ```

  ```python Python theme={"system"}
  config = SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  config.connect_timeout = 2  # connection timeout in seconds
  config.read_timeout = 5  # read timeout in seconds
  config.write_timeout = 30  # write timeout in seconds

  client = SearchClient.create_with_config(config)
  ```

  ```ruby Ruby theme={"system"}
  config = Algolia::Search::Config.new(
    {
      application_id: "ALGOLIA_APPLICATION_ID",
      api_key: "ALGOLIA_API_KEY",
      # read timeout in seconds
      read_timeout: 5,
      # write timeout in seconds
      write_timeout: 30,
      # connect timeout in seconds
      connect_timeout: 2
    }
  )

  client = Algolia::Search::Client.create_with_config(config)
  ```

  ```scala Scala theme={"system"}
  val configuration = AlgoliaClientConfiguration(
    httpConnectTimeoutMs = 2 * 1000, // connection timeout in milliseconds
    httpReadTimeoutMs = 2 * 1000, // read timeout in milliseconds
    httpRequestTimeoutMs = 2 * 1000, // write timeout in milliseconds
    dnsTimeoutMs = 2 * 100, // DNS connection timeout in milliseconds
    hostDownTimeoutMs = 5 * 60 * 1000 // delay before retrying a host we know was down, in milliseconds
  )
  new AlgoliaClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", configuration = configuration)
  ```

  ```swift Swift theme={"system"}
  let configuration = SearchConfiguration(applicationID: "ALGOLIA_APPLICATION_ID", apiKey: "ALGOLIA_API_KEY")
    .set(\.readTimeout, to: 5) // read time out in seconds
    .set(\.writeTimeout, to: 30) // write time out in seconds

  let client = SearchClient(configuration: configuration)
  ```
</CodeGroup>

### Change timeouts for individual requests

<CodeGroup>
  ```cs C# theme={"system"}
  Index index = client.InitIndex("INDEX_NAME");

  RequestOptions requestOptions = new RequestOptions
  {
    // Set the readTimeout to 20 seconds
    Timeout = 20
  };

  var result = index.Search<Result>(new Query("query string"), requestOptions);
  ```

  ```go Go theme={"system"}
  // Set the readTimeout to 20 seconds
  ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)

  opts := []interface{}{
  	ctx,
  }

  res, err := index.Search("query string", opts...)
  ```

  ```java Java theme={"system"}
  SearchIndex<Result> index = client.initIndex("indexName", Result.class);
  Query query = new Query("query string");

  // Set the timeout to 20 seconds
  RequestOptions requestOptions = new RequestOptions()
          .setTimeout(20000);

  // Sync
  SearchResult<Result> search = index.search(query, requestOptions);

  // Async
  CompletableFuture<SearchResult<Result>> search = index.searchAsync(query, requestOptions);
  ```

  ```js JavaScript theme={"system"}
  const index = client.initIndex("ALGOLIA_API_KEY");

  const requestOptions = {
    // Set the readTimeout to 20 seconds
    timeouts: { read: 20 },
  };

  index.search("query string", requestOptions).then(({ hits }) => {
    console.log(hits);
  });
  ```

  ```kotlin Kotlin theme={"system"}
  val indexName = IndexName("INDEX_NAME")
  val index = client.initIndex(indexName)
  val query = Query("query string")
  val requestOptions = requestOptions {
      // Set the readTimeout to 20 seconds
      readTimeout = 20
  }

  index.search(query, requestOptions)
  ```

  ```python Python theme={"system"}
  index = client.init_index("INDEX_NAME")

  request_options = {
      # Set the readTimeout to 20 seconds
      "readTimeout": 20,
  }

  res = index.search("query string", request_options)
  ```

  ```ruby Ruby theme={"system"}
  index = client.init_index("INDEX_NAME")

  request_options = {
    # Set the read_timeout to 20 seconds
    :"read_timeout" => 20
  }

  res = index.search("query string", request_options)
  ```

  ```swift Swift theme={"system"}
  let index = client.index(withName: "INDEX_NAME")
  var requestOptions = RequestOptions()
  // Set the readTimeout to 20 seconds
  requestOptions.readTimeout = 20
  index.search(query: "query string", requestOptions: requestOptions) { result in
    if case .success(let response) = result {
      print("Response: \(response)")
    }
  }
  ```
</CodeGroup>

## Further customization options for JavaScript

This section describes more customization options for the JavaScript API clients.

### Change authentication mode

The JavaScript Search API client lets you change *how* you send your credentials to Algolia.
You can set the `authmode` option to:

* `WithinHeaders` to send the credentials as headers
* `WithinQueryParameters` to send the credentials as URL query parameters.

This option only works with search-related API requests.
Since it doesn't perform a [preflight request](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request),
you should only use it in frontend implementations.

```js JavaScript icon=code theme={"system"}
import { AuthMode } from "@algolia/client-common";

const algoliasearch = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "ALGOLIA_API_KEY",
  {
    authMode: AuthMode.WithinHeaders,
    // authMode: AuthMode.WithinQueryParameters
  },
);
```

The default depends on the environment:

* `algoliasearch/lite` (browser): `WithinQueryParameters`
* `algoliasearch` (browser): `WithinHeaders`
* `algoliasearch` (Node): `WithinHeaders`

### Cache requests and responses

The client caches requests to Algolia and their responses.
You can change the location of your caches, or turn off caching completely.

If you build your own cache,
you must use the [`Cache`](https://github.com/algolia/algoliasearch-client-javascript/blob/master/packages/cache-common/src/types/Cache.ts)
type from `@algolia/cache-common`.

The following cache types are available:

* `NullCache`. No caching for requests and responses. Every method call makes an API request.
* `InMemoryCache`. The client stores requests and responses in memory. When you perform the same query again during your search session, the client reads the results from the cache instead of making a new API request. This avoids duplicate API calls, for example, when a user deletes characters from their current query. Similarly, the client retrieves results from the response cache for queries that you've already performed during your search session.
  The `InMemoryCache` resets on page refresh.
* `LocalStorageCache`. The client stores requests and responses in `localStorage`. When you perform the same query again while the value is still active, the client reads the results from the cache instead of making a new API request. This avoids duplicate API calls, for example, when a user refreshes a page.
  The `LocalStorageCache` resets values when their TTL has been reached.
  When local storage isn't available, for example, when browsing in private mode, it's better to use `BrowserLocalStorageCache` inside `FallbackableCache`.
* `FallbackableCache`. An option to conditionally select one of the other cache types.

These caches are used for:

* `responsesCache`. Caches responses from Algolia. The client stores the response for a query and returns it when you perform the same query again.
* `requestsCache`. Caches promises with the same request payload. The client stores the promise for a request and returns it when you perform the same request again, while the previous request is still pending.

```js JavaScript icon=code theme={"system"}
import { createNullCache } from "@algolia/cache-common";
import { createInMemoryCache } from "@algolia/cache-in-memory";
import { createFallbackableCache } from "@algolia/cache-common";
import { createBrowserLocalStorageCache } from "@algolia/cache-browser-local-storage";

const algoliasearch = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "ALGOLIA_API_KEY",
  {
    // Caches responses from Algolia
    responsesCache: createInMemoryCache(),
    // or another cache, like browserLocalStorageCache
    responsesCache: createFallbackableCache({
      caches: [
        createBrowserLocalStorageCache({
          key: `algolia-responses-${"ALGOLIA_APPLICATION_ID"}-${1}`,
          timeToLive: 60,
        }),
        createInMemoryCache(),
      ],
    }),

    // Caches Promises with the same request payload
    requestsCache: createInMemoryCache({ serializable: false }), // or another cache
  },
);
```

The default cache depends on the environment:

* `algoliasearch/lite` (browser): `InMemoryCache`
* `algoliasearch` (browser): `InMemoryCache`
* `algoliasearch` (Node): `NullCache`

### Cache the state of hosts

The JavaScript API client stores the state of hosts between search requests.
This helps to avoid unreachable hosts.
The state of the hosts remains in the cache for 2 minutes when the host is down.
Whenever a host times out, the API client pushes it to the end of the list of hosts to query on the next request.

You can build a custom cache for hosts as long as it respects the [`Cache`](https://github.com/algolia/algoliasearch-client-javascript/blob/master/packages/cache-common/src/types/Cache.ts) type from `@algolia/cache-common`.

The following cache types are available:

* `NullCache`. No caching for hosts.
* `InMemoryCache`. The client stores the state of hosts in memory. The cache resets on page refresh.
* `BrowserLocalStorageCache`. The client stores the state of hosts in the local storage. Refreshing the page doesn't reset the cache.
  When local storage isn't available, for example, when browsing in private mode, it's better to use `BrowserLocalStorageCache` inside `FallbackableCache`.
* `FallbackableCache`. An option to conditionally select one of the other cache types.

```js JavaScript icon=code theme={"system"}
import { createFallbackableCache } from "@algolia/cache-common";
import { version } from "@algolia/client-common";
import { createInMemoryCache } from "@algolia/cache-in-memory";
import { createBrowserLocalStorageCache } from "@algolia/cache-browser-local-storage";

const algoliasearch = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "ALGOLIA_API_KEY",
  {
    hostsCache: createFallbackableCache({
      caches: [
        createBrowserLocalStorageCache({ key: `${version}-${appId}` }),
        createInMemoryCache(),
      ],
    }), // or createNullCache(), createInMemoryCache()
  },
);
```

The default depends on the environment:

* `algoliasearch/lite` (browser): `FallbackableCache(BrowserLocalStorageCache, InMemoryCache)`
* `algoliasearch` (browser): `FallbackableCache(BrowserLocalStorageCache, InMemoryCache)`
* `algoliasearch` (Node): `InMemoryCache`

For more information, see [Retries and fallback logic](/doc/guides/scaling/infrastructure/classic/distributed-search-network-dsn#retry-strategy).

### Logging

The `logger` option helps you understand more about what's going on with the client.
It accepts any implementation that respects the [Logger](https://github.com/algolia/algoliasearch-client-javascript/blob/master/packages/logger-common/src/types/Logger.ts) type from `@algolia/logger-common`.

These loggers are available:

* `NullLogger`. The client doesn't log anything.
* `ConsoleLogger`.The client logs events with `console.log`.

```js JavaScript icon=code theme={"system"}
import { createNullLogger, LogLevelEnum } from "@algolia/logger-common";
import { createConsoleLogger } from "@algolia/logger-console";

const algoliasearch = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "ALGOLIA_API_KEY",
  {
    logger: createConsoleLogger(LogLevelEnum.Debug), // or createNullLogger
  },
);
```

The client only logs failures that can be retried.
This helps detect anomalies when connecting to Algolia.
The default depends on the environment:

* `algoliasearch/lite` (browser): `ConsoleLogger(LogLevelEnum.Error)`
* `algoliasearch` (browser): `ConsoleLogger(LogLevelEnum.Error)`
* `algoliasearch` (Node): `NullLogger`

### Change HTTP request methods

Use the `requester` option to specify how the client makes network requests.
Your custom implementation must respect the [Requester](https://github.com/algolia/algoliasearch-client-javascript/blob/master/packages/requester-common/src/types/Requester.ts) type from `@algolia/requester-common`.

The following request methods are available:

* `BrowserXhrRequester` uses [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)
* `NodeHttpRequester` uses the [native HTTP Node.js module](https://nodejs.org/api/http.html#http_http)
* `FetchRequester` uses the [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch) API.

```js JavaScript icon=code theme={"system"}
import { createBrowserXhrRequester } from "@algolia/requester-browser-xhr";
import { createNodeHttpRequester } from "@algolia/requester-node-http";
import { createFetchRequester } from "@algolia/requester-fetch";

const algoliasearch = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "ALGOLIA_API_KEY",
  {
    requester: createBrowserXhrRequester(), // or alternatively:
    // requester: createNodeHttpRequester(),
    // requester: createFetchRequester(),
  },
);
```

The default depends on the environment:

* `algoliasearch/lite` (browser): `BrowserXhrRequester`
* `algoliasearch` (browser): `BrowserXhrRequester`
* `algoliasearch` (Node): `NodeHttpRequester`

### Custom user agents

You can use a custom `userAgent` for interacting with Algolia.
This is useful when you're building an integration on top of `algoliasearch`,
or when building custom clients.

#### Add to the default user agent

**Add a string** to the default user agent:

```js JavaScript icon=code theme={"system"}
const searchClient = algoliasearch("ALGOLIA_API_KEY", "ALGOLIA_API_KEY");

searchClient.addAlgoliaAgent("CustomSegment", "x.y.z");
```

This sets the user agent to:

```txt theme={"system"}
Algolia for JavaScript (a.b.c); Browser; CustomSegment (x.y.z)
```

The client uses the following `userAgent` by default:

* `algoliasearch/lite` (browser): `Algolia for JavaScript (a.b.c); Browser (lite);`
* `algoliasearch` (browser): `Algolia for JavaScript (a.b.c); Browser;`
* `algoliasearch` (Node): `Algolia for JavaScript (a.b.c); Node.js;`

#### Replace the default user agent

Replace the user agent information by using the `createUserAgent` function:

```js JavaScript icon=code theme={"system"}
// `version` contains a string with the format "a.b.c"
import { version } from "@algolia/client-common";
import { createUserAgent } from "@algolia/transporter";

const searchClient = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  "INDEX_NAME",
  {
    userAgent: createUserAgent(version).add({
      segment: "CustomSegment",
      version: "x.y.z",
    }),
  },
);
```

This sets the user agent to:

```txt theme={"system"}
Algolia for JavaScript (a.b.c); CustomSegment (x.y.z);
```

Note how this removes the environment ("Browser" or "Node.js") from the user agent string.
By default, `userAgent` is:

* `algoliasearch/lite` (browser): `Algolia for JavaScript (x.x.x); Browser (lite);`
* `algoliasearch` (browser): `Algolia for JavaScript (x.x.x); Browser;`
* `algoliasearch` (Node): `Algolia for JavaScript (x.x.x); Node.js;`

### Keep-alive connections

By default, the JavaScript API client sends requests with the [`Keep-Alive`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive)
header: `Connection: keep-alive`.

To close all remaining connections after you're done interacting with the Algolia API,
use `client.destroy()`:

```js JavaScript icon=code theme={"system"}
const client = algoliasearch("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY");
const index = client.initIndex("INDEX_NAME");

const results = await index.search("query string");

await client.destroy();
```

### Build an API client from scratch

For full control, create your API client from scratch with the `createSearchClient` function.

```js JavaScript icon=code theme={"system"}
import { createBrowserLocalStorageCache } from "@algolia/cache-browser-local-storage";
import { createFallbackableCache } from "@algolia/cache-common";
import { createInMemoryCache } from "@algolia/cache-in-memory";
import { AuthMode, version } from "@algolia/client-common";
import { createSearchClient, multipleQueries } from "@algolia/client-search";
import { LogLevelEnum } from "@algolia/logger-common";
import { createConsoleLogger } from "@algolia/logger-console";
import { createBrowserXhrRequester } from "@algolia/requester-browser-xhr";
import { createUserAgent } from "@algolia/transporter";

const client = createSearchClient({
  appId: "ALGOLIA_APPLICATION_ID",
  apiKey: "ALGOLIA_API_KEY",
  timeouts: {
    connect: 1,
    read: 2,
    write: 30,
  },
  requester: createBrowserXhrRequester(),
  logger: createConsoleLogger(LogLevelEnum.Error),
  responsesCache: createInMemoryCache(),
  requestsCache: createInMemoryCache({ serializable: false }),
  hostsCache: createFallbackableCache({
    caches: [
      createBrowserLocalStorageCache({ key: `${version}-${appId}` }),
      createInMemoryCache(),
    ],
  }),
  userAgent: createUserAgent(version).add({
    segment: "Browser",
    version: "lite",
  }),
  authMode: AuthMode.WithinQueryParameters,
  methods: { search: multipleQueries },
});
```

## Pass options to the PHP HTTP client

The PHP API client lets you override what HTTP layer will be used by the search client.
You can pass custom options to the underlying HTTP client, for example, to configure a proxy.
Choose between these two HTTP clients:

* [Guzzle](https://docs.guzzlephp.org/en/stable/), a popular HTTP client for PHP (recommended)
* A custom HTTP client built on top of curl

### Guzzle HTTP client

See [guzzle options](https://docs.guzzlephp.org/en/stable/request-options.html)

```php PHP icon=code theme={"system"}
<?php
use Algolia\AlgoliaSearch\Algolia;
use GuzzleHttp\Client as GuzzleClient;

$httpClient = new Algolia\AlgoliaSearch\Http\Guzzle6HttpClient(
  new GuzzleClient([
    'proxy' => $proxyAddress,
  ])
);

Algolia::setHttpClient($httpClient);
```

### Default HTTP client based on curl

See [curl options](https://curl.se/libcurl/c/curl_easy_setopt.html).

```php PHP icon=code theme={"system"}
<?php
use Algolia\AlgoliaSearch\Algolia;

$httpClient = new Algolia\AlgoliaSearch\Http\Php53HttpClient([
    'CURLOPT_PROXY' => $strProxy,
    'CURLOPT_FOLLOWLOCATION' => 1,
]);

Algolia::setHttpClient($httpClient);
```
