> ## 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 compression, logging, timeouts, user agent information, headers, and hosts for flexible integrations.

To change the settings for **all requests**, you can initialize the API client with a custom configuration.

To configure individual requests, see [Request options](/doc/libraries/sdk/request-options).

<Note>
  Not all API clients support all customization options.
</Note>

## Custom configuration

Customize the API client by creating a configuration object or by passing additional options when instantiating the client.

<CodeGroup>
  ```cs C# {4,5,6,7} theme={"system"}
  using Algolia.Search.Clients;

  // Create custom configuration
  var config = new SearchConfig(
      appId: "ALGOLIA_APPLICATION_ID",
      apiKey: "ALGOLIA_API_KEY"
  );

  // Customize the configuration ...

  // Instantiate SearchClient with custom configuration
  var client = new SearchClient(config);
  ```

  ```dart Dart {4,5,6} theme={"system"}
  import 'package:algoliasearch/algoliasearch.dart';

  Future<void> main() async {
    final options = ClientOptions(
      // Customize the configuration ...
    );

    final client = SearchClient(
      appId: 'ALGOLIA_APPLICATION_ID',
      apiKey: 'ALGOLIA_API_KEY',
      options: options,
    );
  }
  ```

  ```go Go {10,11,12,13,14,15,16} theme={"system"}
  package main

  import (
   "github.com/algolia/algoliasearch-client-go/v4/algolia/search"
   "github.com/algolia/algoliasearch-client-go/v4/algolia/transport"
  )

  func main() {
   // Create custom configuration
   config := search.SearchConfiguration{
    Configuration: transport.Configuration{
     AppID:  "ALGOLIA_APPLICATION_ID",
     ApiKey: "ALGOLIA_API_KEY",
     // Customize the configuration ...
    },
   }

   // Instantiate SearchClient with custom configuration
   client, err := search.NewClientWithConfig(config)
  }
  ```

  ```java Java {9} theme={"system"}
  package org.example;

  import com.algolia.api.SearchClient;
  import com.algolia.config.ClientOptions;

  public class Main {
      public static void main(String[] args) {
          // Add options through method calls as shown in the other examples on this page
          var options = ClientOptions.builder().build();

          var client = new SearchClient(
              "ALGOLIA_APPLICATION_ID",
              "ALGOLIA_API_KEY",
              options
          );
      }
  }
  ```

  ```js JavaScript {3,4,5} theme={"system"}
  import { searchClient } from "@algolia/client-search";

  const options = {
    // Customize the configuration
  };

  const client = searchClient(
    "ALGOLIA_APPLICATION_ID",
    "ALGOLIA_API_KEY",
    options,
  );
  ```

  ```kotlin Kotlin {7,8,9} theme={"system"}
  package org.example

  import com.algolia.client.api.SearchClient
  import com.algolia.client.configuration.ClientOptions

  fun main() {
      val options = ClientOptions(
          // Customize the configuration ...
      )

      val client = SearchClient(
          appId = "ALGOLIA_APPLICATION_ID",
          apiKey = "ALGOLIA_API_KEY",
          options = options
      )
  }
  ```

  ```php PHP {9,10,11,12} theme={"system"}
  <?php

  require_once realpath(__DIR__.'/vendor/autoload.php');

  use Algolia\AlgoliaSearch\Api\SearchClient;
  use Algolia\AlgoliaSearch\Configuration\SearchConfig;

  // Create custom configuration
  $config = SearchConfig::create(
      appId: 'ALGOLIA_APPLICATION_ID',
      apiKey: 'ALGOLIA_API_KEY',
  );

  // Customize the configuration
  // $config-> ...

  // Instantiate SearchClient with custom configuration
  $client = SearchClient::createWithConfig(config: $config);
  ```

  ```python Python {5,6,7,8} theme={"system"}
  from algoliasearch.search.client import SearchClientSync
  from algoliasearch.search.config import SearchConfig

  # Create custom configuration
  config = SearchConfig(
      app_id="ALGOLIA_APPLICATION_ID",
      api_key="ALGOLIA_API_KEY",
  )

  # Customize the configuration

  # Create client with custom configuration
  client = SearchClientSync(config=config)
  ```

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

  app_id = "ALGOLIA_APPLICATION_ID"
  api_key = "ALGOLIA_API_KEY"

  client = Algolia::SearchClient.create(
    "ALGOLIA_APPLICATION_ID",
    "ALGOLIA_API_KEY"
  )

  # Get the configuration object
  config = client.api_client.config

  # Customize the configuration
  # ...
  ```

  ```scala Scala theme={"system"}
  package org.example

  import algoliasearch.config.ClientOptions
  import algoliasearch.api.SearchClient

  // Add options through method calls as shown in the other examples on this page
  val options = ClientOptions.builder().build()

  @main
  def main(): Unit = {
      val client = SearchClient(
          appId = "ALGOLIA_APPLICATION_ID",
          apiKey = "ALGOLIA_API_KEY",
          clientOptions = options
      )
  }
  ```

  ```swift Swift theme={"system"}
  @preconcurrency import Search

  // Create custom configuration
  let config = try SearchClientConfiguration(
      appID: "ALGOLIA_APPLICATION_ID",
      apiKey: "ALGOLIA_API_KEY",
      // Customize the configuration ...
  )


  // Instantiate SearchClient with custom configuration
  let client = try SearchClient(configuration: config)
  ```
</CodeGroup>

## Adjust timeouts

The following example shows how to adjust the default timeouts for all requests.

<CodeGroup>
  ```cs C# theme={"system"}
  // ...
  config.ReadTimeout = TimeSpan.FromSeconds(100);
  config.WriteTimeout = TimeSpan.FromSeconds(100);
  config.ConnectTimeout = TimeSpan.FromSeconds(100);
  // ...
  ```

  ```dart Dart theme={"system"}
  // ...
  final options = ClientOptions(
    readTimeout = Duration(seconds: 100),
    writeTimeout = Duration(seconds: 100),
    connectTimeout = Duration(seconds: 100),
  );
  // ...
  ```

  ```go Go theme={"system"}
  // ...
  config := search.SearchConfiguration{
   Configuration: transport.Configuration{
    // ...
    ReadTimeout:    100 * time.Second,
    WriteTimeout:   100 * time.Second,
    ConnectTimeout: 100 * time.Second,
   },
  }
  // ...
  ```

  ```java Java theme={"system"}
  // Additional import
  import java.time.Duration`

  // ...
  var options = ClientOptions
      .builder()
      .setConnectTimeout(Duration.ofSeconds(100))
      .setReadTimeout(Duration.ofSeconds(100))
      .setWriteTimeout(Duration.ofSeconds(100))
      .build();
  // ...
  ```

  ```js JavaScript theme={"system"}
  // ...
  const options = {
    // Adjust timeouts
    timeouts: {
      read: 10000,
      write: 10000,
      connect: 10000,
    },
  };
  //
  ```

  ```kotlin Kotlin theme={"system"}
  // Additional imports
  import kotlin.time.DurationUnit
  import kotlin.time.toDuration

  // ...
  val options = ClientOptions(
      connectTimeout = 100.toDuration(DurationUnit.SECONDS),
      readTimeout = 100.toDuration(DurationUnit.SECONDS),
      writeTimeout = 100.toDuration(DurationUnit.SECONDS)
  )
  // ...
  ```

  ```php PHP theme={"system"}
  <?php
  // ...
  $config->setConnectTimeout(100);
  $config->setReadTimeout(100);
  $config->setWriteTimeout(100);
  // ...
  ```

  ```python Python theme={"system"}
  # ...
  config.connect_timeout = 100_000
  config.read_timeout = 100_000
  config.write_timeout = 100_000
  # ...
  ```

  ```ruby Ruby theme={"system"}
  # ...
  config.read_timeout = 10_000
  config.write_timeout = 10_000
  config.connect_timeout = 10_000
  # ...
  ```

  ```scala Scala theme={"system"}
  // Additional imports
  import scala.concurrent.duration.DurationInt

  // ...
  val options = ClientOptions
      .builder()
      // Adjust timeouts
      .withConnectTimeout(100.seconds)
      .withReadTimeout(100.seconds)
      .withWriteTimeout(100.seconds)
      .build()
  // ...
  ```

  ```swift Swift theme={"system"}
  // ...
  let config = try SearchClientConfiguration(
      // ...
      writeTimeout: 100,
      readTimeout: 100,
  )
  // ...
  ```
</CodeGroup>

For more information about these timeouts, see [Request options](/doc/libraries/sdk/request-options#reference).

## Enable compression

Enable gzip compression to reduce the size of request bodies sent to Algolia's servers.
When enabled, POST and PUT request bodies that exceed a minimum size are compressed before sending.

<CodeGroup>
  ```cs C# theme={"system"}
  namespace Algolia;

  using System;
  using Algolia.Search.Clients;
  using Algolia.Search.Http;
  using Algolia.Search.Models.Common;
  using Algolia.Search.Models.Search;

  class Compression
  {
    async Task Main(string[] args)
    {
      // Initialize the client with gzip compression enabled
      // Compression reduces the size of request bodies sent to Algolia
      var client = new SearchClient(
        new SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
        {
          Compression = CompressionType.Gzip,
        }
      );

      // Search with compressed request body
      try
      {
        var result = await client.SearchSingleIndexAsync<Hit>(
          "INDEX_NAME",
          new SearchParams(new SearchParamsObject { Query = "comedy" })
        );
        Console.WriteLine(result);
      }
      catch (Exception e)
      {
        Console.WriteLine(e.Message);
      }
    }
  }

  ```

  ```dart Dart theme={"system"}
  import 'package:algolia_client_search/algolia_client_search.dart';

  void compression() async {
    // Initialize the client with gzip compression enabled
    // Compression reduces the size of request bodies sent to Algolia
    final client = SearchClient(
      appId: 'ALGOLIA_APPLICATION_ID',
      apiKey: 'ALGOLIA_API_KEY',
      options: ClientOptions(compression: 'gzip'),
    );

    try {
      // Search with compressed request body
      final result = await client.searchSingleIndex(
        indexName: "INDEX_NAME",
        searchParams: SearchParamsObject(
          query: "comedy",
        ),
      );
      print(result);
    } catch (e) {
      print("Error: ${e.toString()}");
    }
  }

  ```

  ```go Go theme={"system"}
  package main

  import (
  	"fmt"

  	"github.com/algolia/algoliasearch-client-go/v4/algolia/compression"
  	"github.com/algolia/algoliasearch-client-go/v4/algolia/search"
  	"github.com/algolia/algoliasearch-client-go/v4/algolia/transport"
  )

  func enableCompression() {
  	// Initialize the client with gzip compression enabled
  	// Compression reduces the size of request bodies sent to Algolia
  	cfg := search.SearchConfiguration{
  		Configuration: transport.Configuration{
  			AppID:       "ALGOLIA_APPLICATION_ID",
  			ApiKey:      "ALGOLIA_API_KEY", // #nosec G101 -- credentials are placeholders
  			Compression: compression.GZIP,
  		},
  	}

  	client, err := search.NewClientWithConfig(cfg)
  	if err != nil {
  		panic(err)
  	}

  	// Search with compressed request body
  	result, err := client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(
  		"INDEX_NAME").WithSearchParams(search.SearchParamsObjectAsSearchParams(
  		search.NewEmptySearchParamsObject().SetQuery("comedy"))))
  	if err != nil {
  		panic(err)
  	}

  	_ = result

  	fmt.Println("Search with compression completed successfully")
  }

  ```

  ```java Java theme={"system"}
  package com.algolia;

  import com.algolia.api.SearchClient;
  import com.algolia.config.*;
  import com.algolia.model.search.*;

  public class compression {

    public static void main(String[] args) throws Exception {
      // Initialize the client with gzip compression enabled
      // Compression reduces the size of request bodies sent to Algolia
      SearchClient client = new SearchClient(
        "ALGOLIA_APPLICATION_ID",
        "ALGOLIA_API_KEY",
        ClientOptions.builder().setCompressionType(CompressionType.GZIP).build()
      );

      // Search with compressed request body
      var result = client.searchSingleIndex("INDEX_NAME", new SearchParamsObject().setQuery("comedy"), Hit.class);
      System.out.println(result.getHits());
      client.close();
    }
  }

  ```

  ```js JavaScript theme={"system"}
  import { algoliasearch } from 'algoliasearch';

  // Initialize the client with gzip compression enabled
  // Compression reduces the size of request bodies sent to Algolia
  const client = algoliasearch('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY', {
    compression: 'gzip',
  });

  // Search with compressed request body
  const searchCompression = async () => {
    const result = await client.searchSingleIndex({ indexName: 'movies_index', searchParams: { query: 'comedy' } });
    console.log(result.hits);
  };

  searchCompression()
    .then(() => console.log('Done!'))
    .catch((err) => console.error(err));

  ```

  ```kotlin Kotlin theme={"system"}
  package org.example

  import com.algolia.client.api.SearchClient
  import com.algolia.client.configuration.*
  import com.algolia.client.extensions.*
  import com.algolia.client.model.search.*
  import com.algolia.client.transport.*

  suspend fun main() {
    // Initialize the client with gzip compression enabled
    // Compression reduces the size of request bodies sent to Algolia
    val client =
      SearchClient(
        appId = "ALGOLIA_APPLICATION_ID",
        apiKey = "ALGOLIA_API_KEY",
        options = ClientOptions(compressionType = CompressionType.GZIP),
      )

    // Search with compressed request body
    try {
      val result =
        client.searchSingleIndex(
          indexName = "INDEX_NAME",
          searchParams = SearchParamsObject(query = "comedy"),
        )
      println(result.hits)
    } catch (e: Exception) {
      println(e.message)
    }
  }

  ```

  ```php PHP theme={"system"}
  <?php

  require __DIR__.'/../vendor/autoload.php';
  use Algolia\AlgoliaSearch\Api\SearchClient;
  use Algolia\AlgoliaSearch\Configuration\SearchConfig;

  // Initialize the client with gzip compression enabled
  // Compression reduces the size of request bodies sent to Algolia
  $config = SearchConfig::create('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY')
      ->setCompressionType('gzip')
  ;
  $client = SearchClient::createWithConfig($config);

  // Search with compressed request body
  $result = $client->searchSingleIndex(
      'INDEX_NAME',
      ['query' => 'comedy',
      ],
  );
  var_dump($result);

  ```

  ```python Python theme={"system"}
  from algoliasearch.search.config import SearchConfig
  from algoliasearch.search.client import SearchClientSync


  # Initialize the client with gzip compression enabled
  # Compression reduces the size of request bodies sent to Algolia
  _config = SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  _config.compression_type = "gzip"
  _client = SearchClientSync.create_with_config(config=_config)

  # Search with compressed request body
  _client.search_single_index(
      index_name="INDEX_NAME",
      search_params={
          "query": "comedy",
      },
  )

  ```

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

  # Initialize the client with gzip compression enabled
  # Compression reduces the size of request bodies sent to Algolia
  client = Algolia::SearchClient.create(
    "ALGOLIA_APPLICATION_ID",
    "ALGOLIA_API_KEY",
    compression_type: "gzip"
  )

  # Search with compressed request body
  result = client.search_single_index("INDEX_NAME", Algolia::Search::SearchParamsObject.new(query: "comedy"))
  puts(result)

  ```

  ```scala Scala theme={"system"}
  import algoliasearch.api.SearchClient
  import algoliasearch.config.*
  import algoliasearch.extension.SearchClientExtensions

  import algoliasearch.search.SearchParamsObject
  import scala.concurrent.duration.Duration
  import scala.concurrent.{Await, ExecutionContextExecutor}

  object Compression {
    def main(args: Array[String]): Unit = {
      implicit val ec: ExecutionContextExecutor = scala.concurrent.ExecutionContext.global

      // Initialize the client with gzip compression enabled
      // Compression reduces the size of request bodies sent to Algolia
      val client = SearchClient(
        appId = "ALGOLIA_APPLICATION_ID",
        apiKey = "ALGOLIA_API_KEY",
        clientOptions = ClientOptions
          .builder()
          .withCompressionType(CompressionType.Gzip)
          .build()
      )

      // Search with compressed request body
      try {
        val result = Await.result(
          client.searchSingleIndex(
            indexName = "INDEX_NAME",
            searchParams = Some(
              SearchParamsObject(
                query = Some("comedy")
              )
            )
          ),
          Duration(100, "sec")
        )
        println(result)
      } catch {
        case e: Exception => println(e)
      }
    }
  }

  ```

  ```swift Swift theme={"system"}
  import AlgoliaCore
  import AlgoliaSearch
  import Foundation

  func compression() async throws {
      // Initialize the client with gzip compression enabled
      // Compression reduces the size of request bodies sent to Algolia
      let configuration = try SearchClientConfiguration(
          appID: "ALGOLIA_APPLICATION_ID",
          apiKey: "ALGOLIA_API_KEY",
          compression: .gzip
      )
      let client = SearchClient(configuration: configuration)

      do {
          // Search with compressed request body
          let response: SearchResponse<Hit> = try await client.searchSingleIndex(
              indexName: "INDEX_NAME",
              searchParams: SearchSearchParams.searchSearchParamsObject(SearchSearchParamsObject(query: "comedy"))
          )
          print(response)
      } catch {
          print(error.localizedDescription)
      }
  }

  ```
</CodeGroup>

<Note>
  The JavaScript client only supports compression in Node.js builds.
  Browser and worker builds don't support compression.

  The Kotlin client supports compression on JVM only.
</Note>

## Customize user agent information

The following example shows how to add a custom user agent string to the default.

<CodeGroup>
  ```cs C# theme={"system"}
  // ...
  config.UserAgent.AddSegment("custom c# client", "optional version");
  // ...
  ```

  ```dart Dart theme={"system"}
  // ...
  final options = ClientOptions(
    agentSegments: [
      AgentSegment(value: 'custom dart client', version: 'optional version'),
    ],
  );
  // ...
  ```

  ```go Go theme={"system"}
  // ...
  config := search.SearchConfiguration{
      Configuration: transport.Configuration{
          // ...
          // Completely replace the user agent string
          UserAgent:  "custom go client (optional version)"
      },
  }
  // ...

  // You can get the user agent string from an instance of an API client
  defaultUserAgent := client.GetConfiguration().Configuration.UserAgent
  ```

  ```java Java theme={"system"}
  // ...
  var options = ClientOptions
                  .builder()
                  .addAlgoliaAgentSegment("custom java client", "optional version")
                  .build();
  // ...
  ```

  ```js JavaScript theme={"system"}
  // ...
  client.addAlgoliaAgent("custom javascript client", "optional version");
  // ...
  ```

  ```php PHP theme={"system"}
  // ...
  <?php
  // Additional import
  use Algolia\AlgoliaSearch\Support\AlgoliaAgent;

  // ...
  AlgoliaAgent::addAlgoliaAgent(
      clientName: $client->getClientConfig()->getClientName(),
      segment: 'custom php client',
      version: 'optional version'
  );
  // ...
  ```

  ```ruby Ruby theme={"system"}
  # ...
  client.add_user_agent_segment("custom ruby client", "optional version")
  # ...
  ```

  ```scala Scala theme={"system"}
  // Additional import
  import algoliasearch.config.AgentSegment

  // ...
  val options = ClientOptions
      .builder()
      .withAgentSegments(Seq(AgentSegment("custom scala client"), AgentSegment("optional version")))
      .build();
  // ...
  ```
</CodeGroup>

## Add default headers

The following example shows how to add a custom header to all API requests.

<CodeGroup>
  ```cs C# theme={"system"}
  // ...
  config.DefaultHeaders.Add("extra-header", "greetings");
  // ...
  ```

  ```dart Dart theme={"system"}
  // ...
  final options = ClientOptions(
      headers: <String, dynamic>{
        'extra-header': 'greetings',
      },
    );
  );
  // ...
  ```

  ```go Go theme={"system"}
  // ...
  config := search.SearchConfiguration{
   Configuration: transport.Configuration{
    // ...
    DefaultHeaders: map[string]string{
     "extra-header": "greetings",
    },
   },
  }
  // ...
  ```

  ```java Java theme={"system"}
  // ...
  var options = ClientOptions
      .builder()
      .addDefaultHeader("extra-header", "greetings")
      .build();
  // ...
  ```

  ```js JavaScript theme={"system"}
  // ...
  const options = {
    baseHeaders: {
      // Due to CORS restrictions, you can't use arbitrary headers in browsers
      "extra-header": "greetings",
    },
    // Also works with query parameters
    baseQueryParameters: {
      queryParam: "value",
    },
  };
  // ...
  ```

  ```kotlin Kotlin theme={"system"}
  // ...
  const options = ClientOptions(
      defaultHeaders = mapOf("extra-header" to "greetings")
  )
  // ...
  ```

  ```php PHP theme={"system"}
  <?php
  // ...
  $config->setDefaultHeaders(['extra-header' => 'greetings']);
  // ...
  ```

  ```python Python theme={"system"}
  # ...
  config.headers["extra-header"] = "greetings"
  # ...
  ```

  ```ruby Ruby theme={"system"}
  # ...
  config.header_params[:"extra-header" => "greetings"]
  # ...
  ```

  ```scala Scala theme={"system"}
  // ...
  var options = ClientOptions
      .builder()
      .withDefaultHeaders(Map("extra-header" -> "greetings"))
      .build();
  // ...
  ```

  ```swift Swift theme={"system"}
  // ...
  let config = try SearchClientConfiguration(
      // ...
      defaultHeaders: ["extra-header": "greetings"]
  )
  // ...
  ```
</CodeGroup>

<Note>
  If you use the JavaScript API client in a browser — including when you use [InstantSearch](/doc/guides/building-search-ui/getting-started/js) or [Autocomplete](/doc/ui-libraries/autocomplete/introduction/what-is-autocomplete),
  which rely on the API client — you can't send arbitrary HTTP headers.

  Browsers enforce cross-origin resource sharing ([CORS](https://developer.mozilla.org/en-US/docs/Glossary/CORS)) rules.
  During the `OPTIONS` preflight request,
  the API explicitly lists which headers it accepts in the `access-control-allow-headers` response header.
  Any header not listed there is blocked by the browser.

  To see which headers are allowed, check the `access-control-allow-headers` value in the preflight response in your browser's developer tools.
</Note>

## Logging

You can set a custom logger to enable more or less logging output.

<CodeGroup>
  ```cs C# theme={"system"}
  using Algolia.Search.Clients;
  // Install with `dotnet add package Microsoft.Extensions.Logging.Console`
  using Microsoft.Extensions.Logging;

  var loggerFactory = LoggerFactory.Create(builder =>
  {
      // Log everything from Algolia in the console, including debug logs
      builder.AddFilter("Algolia", LogLevel.Debug).AddConsole();
  });

  var client = new SearchClient(
      "ALGOLIA_APPLICATION_ID",
      "ALGOLIA_API_KEY",
      loggerFactory,
  );
  ```

  ```dart Dart theme={"system"}
  // ...
  final options = ClientOptions(logger: print);
  // ...
  ```

  ```java Java theme={"system"}
  // Additional import
  import com.algolia.config.LogLevel;

  // ...
  var options = ClientOptions
      .builder()
      // Print everything to stdout
      .setLogger(message -> System.out.println(message))
      // Adjust the log level (print all request headers)
      .setLogLevel(LogLevel.HEADERS)
      .build();
  // ...
  ```

  ```kotlin Kotlin theme={"system"}
  // Additional imports
  import io.ktor.client.plugins.logging.Logger
  import io.ktor.client.plugins.logging.LogLevel

  // ...
  val options = ClientOptions(
      // Adjust the log level
      logLevel = LogLevel.ALL,
      // Print everything to stdout
      logger = object : Logger {
          override fun log(message: String) {
              println(message)
          }
      },
  )
  // ...
  ```

  ```php PHP theme={"system"}
  <?php

  // ...
  $config->setDebug(true);
  $config->setDebugFile('path/to/logfile');
  // ...
  ```

  ```scala Scala theme={"system"}
  // Additional imports
  import algoliasearch.config.{ClientOptions, Logging}

  // ...
  var options = ClientOptions
      .builder()
      .withLogging(Logging.Full)
      .build()
  // ...
  ```

  ```swift Swift theme={"system"}
  // ...
  let config = try SearchClientConfiguration(
      // ...
      logLevel: .debug
  )
  // ...
  ```
</CodeGroup>

## Custom hosts

The following example shows how to add your own servers.

<CodeGroup>
  ```js JavaScript theme={"system"}
  // ...
  const options = {
    hosts: [
      {
        // URL of your server without scheme
        url: "YOUR_SERVER_URL",
        // Whether this server can be used for read, write, or both requests
        accept: "readWrite", // read | write | readWrite
        // https or http
        protocol: "https",
        // Optional, if deviating from the default port
        // port: "PORT"
      },
    ],
  };
  // ...
  ```

  ```kotlin Kotlin theme={"system"}
  // Additional imports
  import algolia.config.CallType;
  import algolia.config.Host;

  // ...
  val options = ClientOptions(
      hosts = listOf(
          Host(
              url = "YOUR_SERVER_URL",
              callType = CallType.Read
          ),
          // Add the same server again
          // if you want to use it for both read and write requests
          Host(
              url = "YOUR_SERVER_URL",
              callType = CallType.Write
          )
      )
  )
  // ...
  ```

  ```python Python theme={"system"}
  # Additional import
  from algoliasearch.http.hosts import Host, HostsCollection

  # ...
  config.hosts = HostsCollection(
      hosts=[
          Host(
              # URL without scheme
              url="YOUR_SERVER_URL",
              # Whether to use for read, write, or both requests
              accept=CallType.Read | CallType.Write,
              # scheme: "https" # or "http",
              # port: PORT # if deviating from the default
              # priority: NUMBER # sort priority of this host
          ),
      ],
      # Sort hosts by `priority`
      # reorder_hosts=True
  )
  # ...
  ```

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

  hosts = [
    Algolia::Transport::StatefulHost.new("YOUR_SERVER_URL")
  ]

  config = Algolia::Configuration.new(
    "ALGOLIA_APPLICATION_ID",
    "ALGOLIA_API_KEY",
    hosts
  )

  client = Algolia::SearchClient.create_with_config(config)
  ```

  ```scala Scala theme={"system"}
  // Additional imports
  import algoliasearch.config.{CallType, ClientOptions, Host}

  // ...
  val customHosts = Seq(Host("YOUR_SERVER_URL", Set(CallType.Read, CallType.Write)))

  var options = ClientOptions
      .builder()
      .withHosts(customHosts)
      .build()
  ```

  ```swift Swift theme={"system"}
  // Additional imports
  import Core
  import Foundation

  // ...
  let config = try SearchClientConfiguration(
      // ...
      hosts: [.init(url: URL(string: "YOUR_SERVER_URL"))]
  }

  // ...
  ```
</CodeGroup>

## Custom HTTP clients

The following example shows how to use a custom HTTP client to make requests.

<CodeGroup>
  ```cs C# theme={"system"}
  using Algolia.Search.Clients;

  var config = new SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY");

  // CustomRequester must implement `IHTTPRequester`
  var client = new SearchClient(config, new CustomRequester());
  ```

  ```dart Dart theme={"system"}
  // ...
  final Options = ClientOptions(requester: CustomRequester());
  // ...
  ```

  ```go Go theme={"system"}
  // ...
  type CustomRequester struct {
    client *http.Client
  }

  func NewCustomRequester() *CustomRequester {
    return &CustomRequester{
      client: http.DefaultClient,
    }
  }

  func (r *CustomRequester) Request(req *http.Request, _ time.Duration, _ time.Duration) (*http.Response, error) {
    // This gets printed to stdout before the request
    fmt.Printf("CustomRequester > Request: %s\n", req.URL.String())

    return r.client.Do(req)
  }

  config := search.SearchConfiguration{
      transport.Configuration{
          // ...
          Requester: NewCustomRequester(),
      },
  }
  ```

  ```java Java theme={"system"}
  // ...
  var options = ClientOptions
      .builder()
      // CustomRequester must implement `com.algolia.utils.Requester`
      .setRequester(new CustomRequester())
      .build()
  ```

  ```js JavaScript theme={"system"}
  import { echoRequester } from "@algolia/requester-node-http";
  // ...
  const options = {
    // The first parameter is the status to return
    requester: echoRequester(200),
  };
  // ...
  ```

  ```kotlin Kotlin theme={"system"}
  // ...
  val options = ClientOptions(
      requester = CustomRequester()
  )
  // ...
  ```

  ```php PHP theme={"system"}
  <?php

  require_once realpath(__DIR__.'/vendor/autoload.php');

  use Algolia\AlgoliaSearch\Api\SearchClient;
  use Algolia\AlgoliaSearch\Configuration\SearchConfig;
  use Algolia\AlgoliaSearch\Http\CurlHttpClient;
  use Algolia\AlgoliaSearch\RetryStrategy\ApiWrapper;
  use Algolia\AlgoliaSearch\RetryStrategy\ClusterHosts;

  // Create a custom config
  $config = SearchConfig::create(
      appId: 'ALGOLIA_APPLICATION_ID',
      apiKey: 'ALGOLIA_API_KEY',
  );

  // Get the servers for your Algolia cluster
  $clusterHosts = ClusterHosts::createFromAppId(applicationId: $appID);

  // Create a new HTTP client (implements `HttpClientInterface`)
  $customHttpClient = new CurlHttpClient();

  $apiWrapper = new ApiWrapper(
      http: $customHttpClient,
      config: $config,
      clusterHosts: $clusterHosts,
  );

  // Create a custom Search API client
  $client = new SearchClient(apiWrapper: $apiWrapper, config: $config);
  $client = new SearchClient(config: $config);
  ```
</CodeGroup>

## Configuration forwarding to the ingestion transporter

To use the [`WithTransformation` helper methods](/doc/guides/sending-and-managing-data/send-and-update-your-data/connectors/push#search-api-client-withtransformation-helper-methods),
you must [set the transformation region](/doc/guides/sending-and-managing-data/send-and-update-your-data/connectors/push#set-up-the-transformation-region) on the search client.
This creates an internal ingestion transporter that handles requests to the transformation pipeline.

Each language forwards different configuration options from the search client to this transporter.

<Tabs>
  <Tab title="JavaScript">
    The JavaScript client spreads the full `options` object to the ingestion transporter.
    This includes `appId`, `apiKey`, `region`, hosts, timeouts, headers, compression, user agent, custom requester, caches, and query parameters.
  </Tab>

  <Tab title="Java">
    The Java client passes the full `ClientOptions` object to the ingestion transporter.
    This includes `appId`, `apiKey`, `region`, hosts, timeouts, headers, compression, user agent, custom requester, and query parameters.
  </Tab>

  <Tab title="C#">
    The C# client explicitly copies `appId`, `apiKey`, `region`, hosts, timeouts (`ConnectTimeout`, `ReadTimeout`, `WriteTimeout`), headers (`DefaultHeaders`), and compression to the ingestion transporter.
    User agent, custom requester, and query parameters aren't forwarded.
  </Tab>

  <Tab title="PHP">
    The PHP client forwards `appId`, `apiKey`, `region`, and hosts to the ingestion transporter.
    Timeouts, headers, compression, and other options aren't forwarded.
  </Tab>

  <Tab title="Python">
    The Python client forwards `appId`, `apiKey`, `region`, and hosts to the ingestion transporter.
    Timeouts, headers, compression, and other options aren't forwarded.
  </Tab>

  <Tab title="Go">
    The Go client forwards `appId`, `apiKey`, `region`, and hosts to the ingestion transporter.
    Timeouts, headers, compression, and other options aren't forwarded.
  </Tab>
</Tabs>

## DNS caching (Java)

By default, the JVM caches DNS resolutions infinitely. Since Algolia uses multiple IP addresses for load balancing, you should reduce the time to live (TTL) of the cache.

For example, set the TTL of the cache to 60 seconds:

```java Java icon=code theme={"system"}
java.security.Security.setProperty("networkaddress.cache.ttl", "60");
```
