Direct Answer
LangGraph orchestrates the graph — nodes, state and routing. The proxy binds to whatever web-fetching tool a node calls. Give that node's httpx or requests client a proxy (or set HTTP_PROXY / HTTPS_PROXY on the process for env-aware clients), and that node's requests exit through your German mobile IP. The graph structure and the LLM call stay untouched, so only your page fetches carry the German mobile connection — the model keeps its own connection.
The One Thing Most LangGraph Proxy Guides Get Wrong
LangGraph is a stateful orchestration layer on top of LangChain: you wire nodes into a graph, pass state between them, and route with edges. The common mistake is looking for a proxy setting on the graph. There isn't one — and there shouldn't be.
The proxy binds to the tool that fetches the web, not to the orchestration. A ToolNode doesn't make HTTP requests itself; it runs your tool function, and that function's HTTP client is what talks to the target site. So the proxy goes on whatever the node actually uses to fetch — httpx, requests, or a Playwright browser. Route that through the German mobile proxy and your page fetches leave from a German mobile IP, while the graph and the model connection stay exactly as they were.
Get this right and it's a one-client change inside a single node; look for a graph-level switch and you'll never find it.
Before You Start
You'll need four values from your GermanProxy.io account:
- Host and port of your endpoint
- Username and password
The examples use PROXY_HOST, PORT, USER and PASS as placeholders — replace them with your own. There's no hardware to manage: the proxy is a dedicated mobile connection exposed as a host/port/credentials endpoint.
Install LangGraph and an HTTP client:
pip install langgraph langchain-core httpx
Step 1 — Put the Proxy on the Tool's HTTP Client
The proxy lives inside the tool the node runs. With modern httpx, pass the endpoint to proxy= on the client (the older proxies= argument was removed in httpx 0.28):
import httpx
from langchain_core.tools import tool
PROXY = "http://USER:PASS@PROXY_HOST:PORT"
@tool
def fetch_german_page(url: str) -> str:
"""Fetch a URL through the German mobile proxy and return the HTML."""
# proxy= routes both http:// and https:// through the mobile proxy
with httpx.Client(proxy=PROXY, timeout=30) as client:
resp = client.get(url)
resp.raise_for_status()
return resp.text
If your tool uses requests instead, the shape is a proxies dict:
import requests
PROXIES = {
"http": "http://USER:PASS@PROXY_HOST:PORT",
"https": "http://USER:PASS@PROXY_HOST:PORT",
}
resp = requests.get(url, proxies=PROXIES, timeout=30)
Either way, only this tool's requests carry the German mobile IP.
Step 2 — Run the Tool Inside a Graph Node
ToolNode executes the tool call the model asks for. The graph decides when to fetch; the tool decides how the request leaves — through the proxy:
import httpx
from typing import Annotated, TypedDict
from langchain_core.tools import tool
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
PROXY = "http://USER:PASS@PROXY_HOST:PORT"
@tool
def fetch_german_page(url: str) -> str:
"""Fetch a URL through the German mobile proxy and return the HTML."""
with httpx.Client(proxy=PROXY, timeout=30) as client:
resp = client.get(url)
resp.raise_for_status()
return resp.text
class State(TypedDict):
messages: Annotated[list, add_messages]
# The model node is your own; it decides when to call the tool.
graph = StateGraph(State)
graph.add_node("tools", ToolNode([fetch_german_page]))
graph.add_edge(START, "tools")
graph.add_edge("tools", END)
app = graph.compile()
The fetch_german_page node is the only place the German mobile IP is used. Add your model node and tools_condition routing to close the agent loop; the proxy binding doesn't change.
Step 3 — Or Set the Proxy on the Whole Process
If a node's client reads standard proxy environment variables (httpx and requests both do when you don't pass an explicit proxy), you can bind it at process level instead of per-client:
import os
PROXY = "http://USER:PASS@PROXY_HOST:PORT"
os.environ["HTTP_PROXY"] = PROXY
os.environ["HTTPS_PROXY"] = PROXY
Use the per-client form from Step 1 when you want the German exit on the fetch node only, and a direct connection for, say, an internal-API node in the same graph.
Verify the IP First
Before a real run, confirm the exit IP is a German mobile address. The quickest check is a one-line request through the same proxy:
curl -x "http://USER:PASS@PROXY_HOST:PORT" https://api.ipify.org?format=json
If it returns your own address, the tool's client isn't using the proxy — re-check the proxy= argument or that the env vars reached the process, and that the credentials are in the URL. Confirm the ASN and geolocation look like a German mobile network, not a datacenter range. A full checklist is in verifying your mobile proxy.
Sticky Sessions vs. Rotation
How the graph should handle IPs depends on the task:
- Sticky session — keep the same German mobile IP across a multi-step run (fetch a page, follow a link, extract) so a sequence of node calls looks like one coherent visitor.
- Rotation on demand — request a fresh IP at the proxy between runs to spread load across a longer job.
Keep request rates human-reasonable and cap concurrency. The mechanics are in sticky sessions and IP rotation.
Why a Mobile IP at All
German content is localised. German marketplaces and Google.de serve different results, pricing and stock by country and network. Have a node fetch a German site from a US datacenter range and it measures the wrong market. A German IP gives it the in-country view the task needs.
Mobile IPs carry high IP reputation. German sites filter datacenter ranges aggressively — often a 403 Forbidden within a handful of requests. Mobile IPs sit in shared CGNAT pools used by thousands of real subscribers, so they carry high IP reputation — the reason a mobile IP keeps working where a datacenter range stalls.
For the trade-offs between IP types, see mobile vs residential vs datacenter proxy and, on cost, dedicated mobile vs pay-per-GB residential. For the wider agent picture, see mobile proxies for AI agents.
Scrape Responsibly
A mobile proxy improves reliability for legitimate data collection — it is not a tool to circumvent access controls or platform rules. A graph runs largely unattended, so the responsibility to keep it clean is higher, not lower:
- Respect
robots.txtand each site's terms — bake the check into the fetch tool, not just into intentions. - Throttle — add a delay between node runs and cap concurrency so you don't overload target servers.
- Collect only public data you need, and handle any personal data in line with the GDPR.
- Identify your client honestly — set a truthful
User-Agent; don't impersonate someone else.
Whether a specific task is lawful depends on your jurisdiction and the target's terms — this is general information, not legal advice. See are mobile proxies legal and is web scraping legal in the EU.
[!NOTE]
Note: This article is general information, not legal advice. Whether a specific data-collection task is lawful depends on your jurisdiction, the target site's terms and the data involved.
FAQ
Does LangGraph have built-in proxy support?
No. LangGraph orchestrates the graph — nodes, state and edges. It doesn't make HTTP requests itself. The proxy is set at the HTTP client a tool node uses — httpx, requests or a browser — so that node's requests exit through the proxy while the rest of the graph is unaffected.
Does the proxy affect the LLM call in my graph?
Only if you set it there. The proxy binds to the web-fetching tool a node calls, not to the model. Route the page fetch through the German mobile IP and leave the LLM connection as it is — a node that fetches German pages and a node that calls the model are separate places to configure.
Where exactly do I set the proxy?
On the HTTP client inside the tool node. Pass proxy= to an httpx.Client, or a proxies dict to requests. If the client reads standard proxy env vars, you can instead set HTTP_PROXY / HTTPS_PROXY on the process. Per-client is best when you want the German exit on one node only.
Why do I get a 407 error?
407 Proxy Authentication Required means the username and password didn't reach the proxy. Confirm they're in the proxy URL your tool node uses (http://USER:PASS@PROXY_HOST:PORT). See how to fix 407 proxy authentication required.
Do I need a rotating pool for LangGraph?
No. Pool middlewares exist to pick an IP from many. With one dedicated German endpoint your node points at a single host and rotates on demand at the proxy — nothing to wire into the graph. See dedicated vs shared mobile proxy.
HTTP or SOCKS5?
An HTTP endpoint works with httpx and requests out of the box, which is why the examples use http://. SOCKS5 and OpenVPN are available too; reach for SOCKS5 only when a specific node needs it. If a node drives a real browser, set the proxy on the browser launch instead — see mobile proxy for AI browser agents.
Related guides
- CrewAI Proxy Setup with a Dedicated German Mobile Proxy
- LlamaIndex Proxy Setup with a Dedicated German Mobile Proxy
- LLM Web Scraping: Extract Structured Data From German Sites
Get Started
Give your graph a real German mobile IP to collect from. Start with a German mobile proxy — HTTP/SOCKS5/OpenVPN, sticky sessions, on-demand rotation, fair-use 20 GB/day, from a transparent EU provider. Browse the plans to get started.
Get a German mobile proxy: Real 4G/5G IPs from Germany, fair-use 20 GB/day — see German 4G/5G mobile proxy options or start small with a shared 5G proxy.