How to Use Custom HTTP Clients like httpx with the Anthropic Python SDK

Pass a pre-configured httpx.Client or httpx.AsyncClient instance to the http_client parameter when initializing Anthropic or AsyncAnthropic to override default networking behavior while maintaining full SDK compatibility.

The anthropics/anthropic-sdk-python repository is built entirely on the httpx library, abstracting all HTTP communication through a thin wrapper called BaseClient. By leveraging the http_client parameter, you can inject your own pre-configured httpx instances to fine-tune timeouts, connection limits, and middleware without modifying the SDK source code.

Why Inject a Custom HTTP Client?

When you don't provide an http_client argument, the SDK automatically constructs default clients (DefaultHttpxClient for synchronous operations, DefaultAsyncHttpxClient for async) with sensible defaults for timeouts, connection limits, and redirect following. However, passing a custom client enables you to:

  • Configure specific timeout values for long-running inference requests
  • Set custom connection pool limits for high-throughput applications
  • Implement specific transport layers (Unix sockets, custom TLS configurations)
  • Add middleware via httpx event hooks for logging or request modification
  • Use alternative async transports like aiohttp instead of the default

Passing a Custom httpx Client

The http_client parameter in src/anthropic/_client.py accepts any httpx-compatible instance. The SDK validates the client type in lines 75-84, ensuring you cannot accidentally pass a synchronous client to AsyncAnthropic or vice versa.

Synchronous Custom Clients

For synchronous operations, instantiate Anthropic with a configured httpx.Client:

import httpx
from anthropic import Anthropic

# Build a custom httpx.Client with your own settings

my_client = httpx.Client(
    timeout=httpx.Timeout(30.0),               # 30-second timeout

    limits=httpx.Limits(max_connections=200),  # larger connection pool

    follow_redirects=True,                     # same as SDK default

)

# Hand the client to the SDK

anthropic = Anthropic(
    api_key="my-anthropic-api-key",
    http_client=my_client,
)

response = anthropic.completions.create(
    model="claude-3-opus-20240229",
    max_tokens=256,
    messages=[{"role": "user", "content": "Explain quantum tunnelling"}],
)
print(response.completion)

Relevant source: http_client handling in src/anthropic/_client.py (lines 72-84).

Asynchronous Custom Clients

For async operations, pass an httpx.AsyncClient (or compatible) to AsyncAnthropic:

import httpx
from anthropic import AsyncAnthropic

async_client = httpx.AsyncClient(
    timeout=httpx.Timeout(20.0),
    limits=httpx.Limits(max_connections=50),
)

async_anthropic = AsyncAnthropic(
    api_key="my-key",
    http_client=async_client,
)

response = await async_anthropic.completions.create(
    model="claude-3-sonnet-20240229",
    max_tokens=128,
    messages=[{"role": "user", "content": "What is the capital of France?"}],
)

Supplying the wrong client type raises a clear TypeError during initialization.

Customizing SDK Defaults

If you want to keep the SDK's default networking behavior (socket keep-alive options, automatic proxy handling) but tweak specific settings, use the SDK's default client classes rather than raw httpx.Client.

Extending DefaultHttpxClient

The DefaultHttpxClient and DefaultAsyncHttpxClient classes, defined in src/anthropic/_base_client.py (lines 838-896), inherit from httpx.Client and apply SDK-wide defaults before merging your overrides:

from anthropic import Anthropic, DefaultHttpxClient

# Only override the timeout; everything else stays as the SDK defines it

default_like = DefaultHttpxClient(timeout=10.0)

anthropic = Anthropic(api_key="my-key", http_client=default_like)

These classes handle automatic proxy configuration from environment variables and set socket options that the SDK expects.

Using aiohttp Transport

To use aiohttp as the underlying transport instead of httpx's default, install the optional dependency and use DefaultAioHttpClient:

pip install "anthropic[aiohttp]"
import httpx
from anthropic import AsyncAnthropic, DefaultAioHttpClient

# The SDK's DefaultAioHttpClient wraps httpx-aiohttp and respects SDK defaults

aio_client = DefaultAioHttpClient(
    timeout=httpx.Timeout(20.0),
    limits=httpx.Limits(max_connections=50),
)

async_anthropic = AsyncAnthropic(
    api_key="my-key",
    http_client=aio_client,
)

Relevant source: async default client in src/anthropic/_base_client.py (lines 1520-1534).

Advanced Configuration Patterns

Request Logging with Event Hooks

Because DefaultHttpxClient inherits from httpx.Client, you can use any httpx feature including event_hooks for request/response middleware:

import httpx
from anthropic import Anthropic, DefaultHttpxClient

def log_request(request: httpx.Request):
    print(f"→ {request.method} {request.url}")

client = DefaultHttpxClient(event_hooks={"request": [log_request]})

anthropic = Anthropic(api_key="my-key", http_client=client)

Proxy Configuration

The default client classes automatically read HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and NO_PROXY environment variables via the helper in src/anthropic/_utils/_httpx.py. You can verify this behavior matches the SDK test suite:

import os
from anthropic import DefaultHttpxClient

os.environ["HTTPS_PROXY"] = "https://proxy.example.org"

client = DefaultHttpxClient()
assert any(mount.pattern == "https://" for mount in client._mounts.items())

For custom clients, configure mounts directly on your httpx.Client instance before passing it to the SDK.

How the SDK Handles HTTP Clients Internally

The SDK's internal BaseClient class serves as the abstraction layer for all HTTP operations. When you provide a custom client:

  1. Validation: src/anthropic/_client.py checks that the client type matches the sync/async nature of the Anthropic client class
  2. Default Construction: If you pass None, the SDK instantiates _DefaultHttpxClient or _DefaultAsyncHttpxClient from src/anthropic/_base_client.py
  3. Transport Setup: Default clients build a custom transport that adds socket keep-alive options and merges proxy configurations from environment variables
  4. Lifecycle Management: The SDK uses your client for all requests but does not automatically close it, allowing connection reuse across multiple SDK instances

Summary

  • Pass custom httpx.Client or httpx.AsyncClient instances via the http_client parameter to Anthropic or AsyncAnthropic
  • Match synchronous clients to Anthropic and asynchronous clients to AsyncAnthropic to avoid TypeError exceptions
  • Use DefaultHttpxClient or DefaultAsyncHttpxClient to preserve SDK networking defaults while tweaking specific settings like timeouts
  • Install anthropic[aiohttp] and use DefaultAioHttpClient to use aiohttp as the underlying async transport
  • The SDK respects all httpx configuration including timeout, limits, transport, mounts, and event_hooks

Frequently Asked Questions

Can I use aiohttp instead of httpx with the Anthropic SDK?

Yes. Install the optional dependency with pip install "anthropic[aiohttp]" and pass an instance of DefaultAioHttpClient (or any httpx.AsyncClient configured with the aiohttp transport) to the http_client parameter of AsyncAnthropic. This is implemented in src/anthropic/_base_client.py.

What happens if I pass the wrong client type to the SDK?

The SDK validates the client type in src/anthropic/_client.py (lines 75-84). Passing a synchronous httpx.Client to AsyncAnthropic or an httpx.AsyncClient to the synchronous Anthropic class raises a clear TypeError indicating the expected client type for that class.

How do I configure proxy settings when using a custom HTTP client?

When using DefaultHttpxClient or DefaultAsyncHttpxClient, the SDK automatically reads HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables via the helper in src/anthropic/_utils/_httpx.py. For fully custom clients, configure the mounts parameter directly on your httpx.Client instance before passing it to the SDK.

Will the SDK close my custom HTTP client automatically?

No. The SDK deliberately does not close custom clients passed via http_client to avoid interfering with connection reuse patterns. You must manage the client lifecycle yourself, including calling .close() or using the client as a context manager (with httpx.Client() as client:) in your application code.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →