Proxy Setup for LangChain, CrewAI and Claude Agents: A Developer's Guide (2026)

Most agent tutorials skip the proxy part entirely. Then your WebBaseLoader hits a 403 on the first production run, and you're debugging it with no documentation in sight.

Code on a developer screen representing LangChain proxy setup and AI agent configuration guide 2026
TL;DR

Proxy setup for AI agents splits into two completely separate problems. One is routing your LLM API calls through a proxy. The other is routing the web requests your agent's tools make. Most guides cover neither clearly. Here's what actually works.

  • LangChain proxy setup: set HTTP_PROXY and HTTPS_PROXY before importing LangChain. For WebBaseLoader, pass a proxies dict via requests_kwargs for component-level control without touching env vars.
  • CrewAI proxy setup: env vars work for most tool requests. Per-agent proxy assignment requires setting proxy env vars inside custom tool functions. CrewAI uses httpx internally for MCP connections, so SOCKS5 requires pip install socksio.
  • Claude Agents: use ANTHROPIC_BASE_URL to route API calls to a proxy. Use HTTP_PROXY / HTTPS_PROXY for system-wide routing.
  • Proxy type matters. Datacenter IPs get blocked on Google, DuckDuckGo, and most content sites your agents crawl. Rotating residential or hybrid proxies are the correct tool for production agents.
  • Order of operations is critical. Set proxy env vars before any framework imports. Caching at import time is a real gotcha that will waste your afternoon.

The problem with most AI agent proxy guides is they treat proxy setup as an afterthought. You get a code snippet with placeholder credentials, no explanation of which requests it actually covers, and nothing about the five ways it silently fails in production. This guide covers LangChain proxy setup, CrewAI, and Claude agents with working code for each. I've also included the common failure modes I've seen in real pipelines, because those are the things that cost the most time to debug.


The Two Proxy Problems You're Actually Dealing With

Before touching any configuration, understand what you're actually routing. AI agent pipelines make two distinct types of outbound requests, and they need proxy configuration in different places.

Request Type What It Is Where It's Configured Why You Need a Proxy
LLM API calls Your agent calling OpenAI, Anthropic, etc. ANTHROPIC_BASE_URL or SDK-level proxy client Corporate network restrictions, cost routing, audit logging, API gateway control
Tool web requests Agent tools fetching web pages, search results, APIs HTTP_PROXY env vars or per-component kwargs Rate limiting, IP bans, geo-restrictions, bot detection on target sites

Most developers hitting proxy issues are dealing with the tool request problem: their agent's WebBaseLoader can't load pages because the datacenter IP got blocked, or DuckDuckGoSearchRun starts returning empty results after 50 queries because it's rate-limiting the IP. That's a residential rotating proxy problem. Nothing to do with how you're calling Claude or GPT-4.

Corporate network restrictions are the LLM API call problem. You're behind a firewall that blocks direct connections to api.anthropic.com. That's a different configuration entirely.

Know which problem you have before picking a solution.


LangChain Proxy Setup

LangChain's tools and document loaders use Python's requests library for most HTTP calls. That means they respect HTTP_PROXY and HTTPS_PROXY environment variables natively. The catch: they read these variables at import time in some components, not at request time. Set them before your imports.

Method 1: Environment Variables (Global)

Python Set before ALL imports
import os

# Set proxy BEFORE importing any LangChain components
os.environ["HTTP_PROXY"]  = "http://username:password:[email protected]:6011"
os.environ["HTTPS_PROXY"] = "http://username:password:[email protected]:6011"

# Now import LangChain
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import ChatOpenAI

This covers DuckDuckGoSearchRun, BingSearchAPIWrapper, GoogleSearchAPIWrapper, and most other tools that use requests under the hood. It's the lowest-friction approach for development.

Method 2: WebBaseLoader with requests_kwargs

This is the cleaner approach for production. Instead of polluting env vars globally, pass proxy configuration directly to the loader. It also means different loaders can use different proxies, which matters when you're hitting geo-locked content and need region-specific IPs.

Python Component-level proxy control
from langchain_community.document_loaders import WebBaseLoader

proxy_config = {
    "http":  "http://username:password:[email protected]:6011",
    "https": "http://username:password:[email protected]:6011",
}

loader = WebBaseLoader(
    web_paths=["https://example.com/page"],
    requests_kwargs={
        "proxies": proxy_config,
        "timeout": 30,
        "headers": {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        }
    }
)

docs = loader.load()
print(docs[0].page_content[:500])
Always Set a User-Agent
WebBaseLoader's default User-Agent is a Python requests string. Sites with basic bot detection block it immediately. Pass a real browser User-Agent via requests_kwargs. The proxy gets you past IP-based detection. The User-Agent handles the header check.

SOCKS5 Proxy in LangChain

TorchProxies supports SOCKS5 via the socksgeox.torchproxies.com host on port 6014. SOCKS5 routes all TCP traffic, not just HTTP, which is useful for tools that make non-HTTP requests. The setup is almost identical, but you need the requests[socks] package.

Shell Install SOCKS support first
pip install requests[socks]
Python SOCKS5 configuration
import os

os.environ["HTTP_PROXY"]  = "socks5://username:password:[email protected]:6014"
os.environ["HTTPS_PROXY"] = "socks5://username:password:[email protected]:6014"

from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://example.com")
docs = loader.load()

Async LangChain (AsyncHtmlLoader)

If you're running async agents or using AsyncHtmlLoader, the proxy configuration is different. Async components use aiohttp or httpx, not the requests library. Environment variables don't propagate to these clients automatically.

Python Async loader with aiohttp proxy
import asyncio
import aiohttp
from langchain_community.document_loaders import AsyncHtmlLoader

async def load_with_proxy(urls: list[str]) -> list:
    proxy_url = "http://username:password:[email protected]:6011"

    # Pass proxy via requests_per_second and header settings
    loader = AsyncHtmlLoader(
        urls,
        proxies={"http://": proxy_url, "https://": proxy_url},
        requests_per_second=2
    )
    return await loader.aload()

docs = asyncio.run(load_with_proxy(["https://example.com"]))
The Silent Failure Trap
If you set env vars after importing LangChain, some components won't pick them up. The requests go out on your real IP. No error is thrown. You just get blocked responses and wonder why the proxy isn't working. Always set the env vars at the very top of your script, before any imports from LangChain.
S
Sachin Supunthaka — Senior Software Engineer
The thing is, when I'm debugging an agent that's getting blocked despite a proxy being configured, the first thing I check is import order. It catches the problem more often than you'd expect. The second thing I check is whether the specific component uses requests or httpx. LangChain has been gradually migrating some components to httpx, and those components need an explicitly configured httpx client rather than just env vars. Check the source of the component you're using if env vars aren't working. The answer is usually in there.

CrewAI Proxy Setup

CrewAI's architecture matters here. An agent crew has agents, tasks, and tools. The proxy configuration needs to cover the tools, because that's where the web requests actually happen. The agents themselves just orchestrate LLM calls; those are handled by LangChain's chat models underneath.

Global Proxy via Environment Variables

Simplest approach. Set env vars before importing CrewAI, and all outbound requests from tools pick them up.

Python Global proxy for all CrewAI tool requests
import os

# Must be set before importing crewai
os.environ["HTTP_PROXY"]  = "http://username:password:[email protected]:6011"
os.environ["HTTPS_PROXY"] = "http://username:password:[email protected]:6011"

from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool, WebsiteSearchTool

search_tool = SerperDevTool()
web_tool    = WebsiteSearchTool()

researcher = Agent(
    role="Market Researcher",
    goal="Gather competitive intelligence from target sites",
    backstory="Expert at finding and extracting market data",
    tools=[search_tool, web_tool],
    verbose=True
)

Per-Agent Proxy Assignment

This is the pattern most guides skip. When you're running a crew with agents that scrape different target types, you want each agent on a different IP. A researcher hitting news sites doesn't need the same proxy subnet as an agent scraping e-commerce product pages. Identity isolation matters at scale.

The cleanest way to do it: wrap your tool calls inside custom tool classes and set the proxy environment variables at call time.

Python Per-agent proxy via custom tool wrapper
import os
import requests
from crewai_tools import BaseTool
from pydantic import Field

class ProxiedWebFetcher(BaseTool):
    name: str = "Proxied Web Fetcher"
    description: str = "Fetches a URL through a dedicated proxy"
    proxy_url: str = Field(description="Proxy URL for this agent")

    def _run(self, url: str) -> str:
        proxies = {
            "http":  self.proxy_url,
            "https": self.proxy_url,
        }
        response = requests.get(
            url,
            proxies=proxies,
            timeout=30,
            headers={"User-Agent": "Mozilla/5.0 (compatible; ResearchBot/1.0)"}
        )
        response.raise_for_status()
        return response.text[:5000]

# Each agent gets its own proxy
researcher_tool  = ProxiedWebFetcher(proxy_url="http://user:pass:[email protected]:6011")
analyst_tool     = ProxiedWebFetcher(proxy_url="http://user:pass:[email protected]:6011")

CrewAI and SOCKS5: The socksio Requirement

CrewAI uses httpx internally for MCP server connections and some tool requests. If you're routing through a SOCKS5 proxy, httpx needs the socksio package to handle that protocol. Without it, you get a cryptic error.

Shell Required for SOCKS5 in CrewAI
pip install socksio httpx
Python SOCKS5 with httpx for CrewAI MCP tools
import httpx

# Configure httpx client with SOCKS5 proxy
proxy_client = httpx.Client(
    proxy="socks5://username:password:[email protected]:6014",
    timeout=30
)

# Use this client in tools that accept an httpx client parameter
# For env-var-based routing:
import os
os.environ["HTTP_PROXY"]  = "socks5://username:password:[email protected]:6014"
os.environ["HTTPS_PROXY"] = "socks5://username:password:[email protected]:6014"

Claude Agents Proxy Setup

Claude Agents and Claude Code support two distinct proxy methods, and they solve different problems. One routes the API calls themselves. The other routes everything.

ANTHROPIC_BASE_URL: Routing LLM API Calls

This is the cleanest way to put something between your agent and Anthropic's API. Set ANTHROPIC_BASE_URL to point at your proxy, and every sampling request goes through it. Your proxy receives the full plaintext request, can inspect or modify it (injecting credentials, adding logging, rate limiting), then forwards to api.anthropic.com.

Shell Claude Code CLI with a proxy
# Route all Claude API calls through your proxy
export ANTHROPIC_BASE_URL=http://your-proxy-server:8080
export ANTHROPIC_API_KEY=sk-ant-...

# Claude Code automatically uses ANTHROPIC_BASE_URL
claude
Python Anthropic SDK with custom base URL
import anthropic

# Custom base URL routes API calls through your proxy
client = anthropic.Anthropic(
    api_key="sk-ant-...",
    base_url="http://your-proxy-server:8080"
)

message = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}]
)

HTTP_PROXY / HTTPS_PROXY: System-Wide Routing

For routing all Claude agent traffic through a proxy, including both API calls and any tool-based web requests, use the standard environment variables.

Shell System-wide proxy for all Claude Code traffic
export HTTP_PROXY=http://username:password:[email protected]:6011
export HTTPS_PROXY=http://username:password:[email protected]:6011

# Claude Code and the Agent SDK respect these variables
claude
Python httpx client proxy for Anthropic SDK (advanced)
import httpx
import anthropic

# Fine-grained control: configure the underlying httpx client directly
http_client = httpx.Client(
    proxy="http://username:password:[email protected]:6011"
)

client = anthropic.Anthropic(
    api_key="sk-ant-...",
    http_client=http_client
)

# All SDK requests now go through the proxy
ANTHROPIC_BASE_URL vs HTTP_PROXY
Use ANTHROPIC_BASE_URL when you want to inspect or modify Claude API requests, inject credentials, or route through an API gateway. Your proxy receives plaintext and can read the full request body. Use HTTP_PROXY when you want system-wide routing without needing to inspect content. The Claude SDK sees an opaque TLS tunnel for HTTPS services. For tool-based web requests alongside API calls, set both.

Choosing the Right Proxy Type for Your Agent's Web Access

Datacenter proxies get blocked. That's the short answer for anyone shipping a production agent that scrapes real sites. Search engines, news sites, e-commerce platforms, any site running Cloudflare Bot Management: they all block datacenter IP ranges either immediately or after a few requests.

For most agent tool requests, rotating residential proxies handle the job. Your agent's WebBaseLoader and search tools see clean IPs on each request, and the target sites treat them as regular consumer traffic.

Agent Use Case Proxy Type Why TorchProxies Product
Research agents (news, Google, DuckDuckGo) Rotating Residential Search engines rate-limit datacenter IPs fast. Residential IPs look like normal user queries. Plan X or Premium Residential
Web scraping agents (e-commerce, product data) Hybrid (ISP + Residential) Protected targets need ASN diversity. One burned subnet doesn't take down the whole pipeline. Plan X at $5/GB
Authenticated agent workflows (login sessions) ISP Static Login sessions need consistent IP identity. Rotation triggers security challenges. ISP Static at $2.3/IP/month
Multi-region agents (geo-locked content) Residential with City Targeting Content differs by region. City-level targeting lets you specify exactly where requests appear to come from. Premium Residential at $4.5/GB
High-frequency scraping agents (1000+ req/day) Hybrid (Plan X) High volume burns through a single residential ASN. Mixed residential and ISP sources spread the load across ASNs. Plan X at $5/GB

One thing worth flagging: rotating proxies and authenticated sessions don't mix. If your agent needs to log in and maintain a session across multiple requests, set sticky sessions on the proxy. TorchProxies supports sticky sessions configurable from the dashboard. Without this, each request gets a new IP, the session breaks, and your agent spends half its time re-authenticating.


Production Patterns Worth Knowing

Retry Logic With Backoff

Agents hitting protected sites will get 429s and 403s despite clean proxies. Sometimes it's a rate limit. Sometimes the IP rotation hasn't kicked in yet. Your agent needs to handle these gracefully rather than failing the entire task.

Python Retry wrapper for agent tool requests
import time
import requests
from requests.exceptions import ProxyError, ConnectionError

def fetch_with_retry(url: str, proxies: dict, max_retries: int = 3) -> str:
    wait = 2
    for attempt in range(max_retries):
        try:
            response = requests.get(
                url,
                proxies=proxies,
                timeout=30,
                headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
            )
            if response.status_code == 429:
                time.sleep(wait)
                wait *= 2  # Exponential backoff
                continue
            response.raise_for_status()
            return response.text

        except (ProxyError, ConnectionError) as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(wait)
            wait *= 2

    raise Exception(f"Failed to fetch {url} after {max_retries} attempts")

Testing Your Proxy Before Running the Agent

Spending 30 seconds on this before a long-running agent job is worth it. Proxy failures mid-run are expensive, especially if you're paying per token for the LLM calls the agent is already making.

Python Quick proxy health check
import requests

def verify_proxy(proxy_url: str) -> bool:
    proxies = {"http": proxy_url, "https": proxy_url}
    try:
        r = requests.get(
            "https://httpbin.org/ip",
            proxies=proxies,
            timeout=10
        )
        data = r.json()
        print(f"Proxy IP: {data['origin']}")
        return True
    except Exception as e:
        print(f"Proxy check failed: {e}")
        return False

# Run this before your agent starts
proxy_url = "http://username:password:[email protected]:6011"
if not verify_proxy(proxy_url):
    raise RuntimeError("Proxy unreachable. Check credentials and endpoint.")

A Note on .env Files

If you're loading proxy credentials from a .env file via python-dotenv, make sure load_dotenv() runs before any LangChain or CrewAI imports. The same import-time caching issue applies. Structure your entry point like this:

Python main.py — correct order
# 1. Load env FIRST
from dotenv import load_dotenv
load_dotenv()

# 2. Then import everything else
from langchain_community.document_loaders import WebBaseLoader
from crewai import Agent, Task, Crew
import anthropic

This is worth getting right before you scale. A subtle import order bug doesn't surface in development on your own IP. It surfaces at 2am when a production agent is halfway through a crawl job.


TorchProxies for AI Agents

From the dashboard, generate credentials and select the proxy type that matches your agent's workload. Plan X proxies use pool-specific hosts and ports — the global residential pool (geox) runs on port 6011, and the SOCKS5 endpoint (socksgeox) runs on port 6014. Targeting parameters (country, city, session) are appended to the credentials in the proxy string.

For research agents hitting search engines and news sites, Plan X at $5/GB is the right starting point. The hybrid infrastructure combines over 50 million real residential IPs with dedicated ISP proxy pools, giving you a choice between authentic residential traffic for maximum trust and unlock rates, or ISP proxies for speed-sensitive operations. Country, city, and state targeting are set directly in the proxy string by appending parameters after the password — no separate dashboard configuration needed.

For authenticated agent workflows where the same account session needs to persist across multiple requests, ISP Static proxies at $2.3/IP/month give you a fixed dedicated IP that doesn't rotate. For Plan X sticky sessions, append a session-XXXXXXXX parameter directly to the proxy string (exactly 8 lowercase alphanumeric characters). Sessions persist for up to 168 hours.

No rate limits on any plan. Free trial available without a credit card. Pay-as-you-go on bandwidth, so you're only paying for what your agents actually use.

Python Full LangChain agent setup with TorchProxies Plan X
import os
from dotenv import load_dotenv

load_dotenv()

# TorchProxies credentials from env
TORCH_USER = os.environ["TORCHPROXIES_USER"]
TORCH_PASS = os.environ["TORCHPROXIES_PASS"]
# Plan X: pool-specific host + port; targeting params after password
PLAN_X_HOST = "geox.torchproxies.com"  # global residential pool
PLAN_X_PORT = "6011"
COUNTRY     = "country-us"  # use city-boston or session-a1b2c3d4 for additional targeting

os.environ["HTTP_PROXY"]  = f"http://{TORCH_USER}:{TORCH_PASS}:{COUNTRY}@{PLAN_X_HOST}:{PLAN_X_PORT}"
os.environ["HTTPS_PROXY"] = f"http://{TORCH_USER}:{TORCH_PASS}:{COUNTRY}@{PLAN_X_HOST}:{PLAN_X_PORT}"

from langchain_community.tools import DuckDuckGoSearchRun
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain import hub

llm        = ChatOpenAI(model="gpt-4o", temperature=0)
search     = DuckDuckGoSearchRun()
tools      = [search]
prompt     = hub.pull("hwchase17/react")
agent      = create_react_agent(llm, tools, prompt)
executor   = AgentExecutor(agent=agent, tools=tools, verbose=True)

result = executor.invoke({"input": "What are the top AI companies in 2026?"})
print(result["output"])

Proxies Built for AI Agents

120M+ IPs. No rate limits. HTTP, HTTPS, SOCKS5 on every plan. Free trial, no credit card.

Start Free Trial

Plan X from $5/GB  ·  ISP Static from $2.3/IP/month  ·  180+ Countries  ·  Pay-As-You-Go

Quick Reference

Framework Proxy Configuration at a Glance
LangChain (global) Set HTTP_PROXY and HTTPS_PROXY before importing. Works for DuckDuckGoSearchRun, WebBaseLoader, RequestsGetTool.
LangChain WebBaseLoader (precise) Use requests_kwargs={"proxies": {...}} for component-level control. Include User-Agent.
CrewAI (global) Env vars before importing crewai. SOCKS5 requires pip install socksio for httpx-based tools.
CrewAI (per-agent) Wrap tools in a custom BaseTool subclass. Set proxies inside _run() at call time.
Claude Agents (API calls) Set ANTHROPIC_BASE_URL to your proxy. Claude Code and the Anthropic SDK both respect it.
Claude Agents (all traffic) Set HTTP_PROXY and HTTPS_PROXY. Routes both API calls and tool web requests.

Frequently Asked Questions

Two approaches. The simplest: set HTTP_PROXY and HTTPS_PROXY environment variables before importing LangChain. This proxies all tool requests automatically. For component-level control, pass a proxies dict to WebBaseLoader via requests_kwargs={"proxies": {...}}. Always set env vars before any LangChain imports. Setting them after causes silent failures where requests go out on your real IP.
Yes. Set HTTP_PROXY and HTTPS_PROXY before importing CrewAI. For per-agent identity isolation, wrap tool requests in a custom BaseTool subclass and set proxies inside _run(). CrewAI uses httpx for MCP connections, so SOCKS5 requires pip install socksio. Without that package, SOCKS5 proxies throw a cryptic package-not-found error.
Two methods. Set ANTHROPIC_BASE_URL to your proxy server address, and all Claude API calls route through it in plaintext, where your proxy can inspect or modify them. Or set HTTP_PROXY and HTTPS_PROXY for system-wide routing of all traffic. Claude Code CLI and the Anthropic SDK both respect both approaches. Use ANTHROPIC_BASE_URL if you need to inspect request content. Use HTTP_PROXY if you just want routing without interception.
Rotating residential proxies for most agent tool requests. Datacenter IPs get blocked by search engines and any site running anti-bot protection. Residential IPs pass IP reputation checks. For high-frequency scraping or targets with heavy protection, hybrid proxies (Plan X at $5/GB) distribute requests across residential and dedicated ISP pools, which reduces the risk of any one subnet getting rate-limited. For authenticated sessions requiring IP consistency, ISP static proxies at $2.3/IP/month are the right fit.
Two main causes. First, env vars set after LangChain imports don't propagate to some components. Set them before any imports. Second, some LangChain components use httpx rather than requests, and httpx doesn't pick up HTTP_PROXY by default. For those components, pass an explicitly configured httpx client. Also check your User-Agent: WebBaseLoader's default Python requests string gets blocked on sites with basic header inspection, regardless of IP.