Gemini network proxy: configure and diagnose a client connection

11 min read

Route google-genai through an HTTP CONNECT proxy, keep TLS on, and tell a dead hop from an API refusal without treating a tunnel as Google access.

This guide is for developers who need google-genai 2.30.1 to leave through an HTTP CONNECT proxy. The checks used a loopback origin and a dummy hop, not a Google account. Top Proxy does not sell IPs, and there are no free keys here. A working tunnel is not API access.

01Pick one Gemini client and pin it

Gemini is a family of products. The consumer web app, the Gemini Developer API, Vertex AI or Gemini Enterprise Agent Platform, and the Gemini CLI do not share a proxy knob. Mixing them is how you debug a browser while your Python process still goes direct. This walkthrough stays on one client: the Google Gen AI Python SDK talking to the Gemini Developer API.

Gemini API docs, accessed 15 October 2026, last updated 13 October 2026 UTC, describe that API as the path from prompt to production. They do not document a proxy. Proxy wiring lives in the SDK README. Available regions, last updated 28 April 2026, is a country list for AI Studio and the API. A proxy does not add a missing region, a verified age, or a billing account.

Pin what you import. This run used Python 3.14.6, google-genai 2.30.1, httpx 0.28.1, and LibreSSL 3.3.6 as the openssl binary for a lab CA. PyPI listed 2.30.1 the same day. The installed client defaulted the Gemini Developer API to https://generativelanguage.googleapis.com/ and v1beta. Vertex uses a different constructor and a different host. Leave it alone here.

  1. Create a venv on the Python you will actually run. This machine used /opt/homebrew/bin/python3.14.
  2. Install google-genai==2.30.1. Do not let a later wheel rewrite the HTTP stack under you.
  3. Print versions before you touch a proxy. Keep the google-genai and httpx lines.
Pinned google-genai 2.30.1, httpx 0.28.1, Python 3.14.6, LibreSSL 3.3.6

The README, Proxy section around the httpx default, says the SDK uses httpx for both sync and async clients. google-genai[aiohttp] is an extra for a faster async path, with trust_env=True to match httpx. That extra was not installed in this run. I am not going to pretend aiohttp routed anything. SOCKS5 is documented only after httpx[socks] and HttpOptions.client_args. Also untested here. HTTP CONNECT is the path that actually moved.

Pass api_key into genai.Client or set GEMINI_API_KEY / GOOGLE_API_KEY before init. API key setup is account work. The lab used the dummy string lab-not-a-google-key against a loopback origin. That key never left the machine toward Google.

02Set HTTPSPROXY before you construct Client

The README is blunt. Both httpx and aiohttp read urllib.request.getproxies from the environment. Set the proxy before you construct the client:

export HTTPS_PROXY='http://USER:PASS@PROXY_HOST:PROXY_PORT'
export SSL_CERT_FILE='/path/to/extra-ca.pem'

SSL_CERT_FILE is optional. Production Gemini on public CAs does not need a private CA file. The lab needed one because the origin certificate was minted locally. Installed 2.30.1 does extra work here. _api_client.py builds an SSL context with ssl.create_default_context(cafile=os.environ.get('SSL_CERT_FILE', certifi.where())) because, in the SDK authors' words, httpx does not pull SSL_CERT_FILE on its own. Export the variable before Client(...). Exporting it later will not retrofit a live client.

Userinfo in HTTPS_PROXY is proxy authentication. It is not your Gemini API key. Put the API key in Client(api_key=...) or in GEMINI_API_KEY. If you dump the proxy URL into a log, redact the password. Process listings still see the environment for a moment.

The same README shows SOCKS5 through httpx args, not through HTTPS_PROXY:

from google import genai
from google.genai import types

client = genai.Client(
    api_key="YOUR_API_KEY",
    http_options=types.HttpOptions(
        client_args={"proxy": "http://USER:PASS@PROXY_HOST:PROXY_PORT"},
        timeout=60000,
        retry_options=types.HttpRetryOptions(attempts=1),
    ),
)

HttpOptions.timeout is milliseconds. 2.30.1 converts it with / 1000.0 before httpx. retry_options=None on this build means tenacity stops after one attempt. Troubleshooting still says the Python SDK retries transient errors up to four times with about 1s then 60s max. That page is dated 13 October 2026. The installed client does not do that unless you pass HttpRetryOptions. I would rather set attempts=1 while I diagnose a hop than watch a dead port get exponential backoff.

  1. Export only HTTPS_PROXY if the target is HTTPS, which Gemini is. This run did not set HTTP_PROXY. urllib.request.getproxies() then returned {'https': 'http://127.0.0.1:62748'}.
  2. Keep NO_PROXY empty when you intend the proxy to see loopback. A leftover NO_PROXY=localhost will skip the hop and look like a success.
  3. Construct genai.Client after the environment is set. Close it when you are done.

Explicit client_args={'proxy': ...} is the other documented door. It also sent CONNECT in this run. Use it when a shell already owns HTTPS_PROXY and you do not want to fight it.

03Prove the route on a target you control

Status 200 is a poor witness. Direct and proxied calls can both return 200. You need a hop log or an origin stamp. The lab pointed HttpOptions.base_url at https://127.0.0.1:PORT/ so google-genai never opened generativelanguage.googleapis.com. The origin answered with JSON labeled SIMULATED. That is routing proof. It is not a model answer, a quota check, or a region pass.

Your own check can be smaller than a public lab. You need the installed client, a proxy you own, and a target you own. Loopback is enough. Do not turn verify off. Do not point this at Google until the hop is boring.

import os
from google import genai
from google.genai import types

os.environ["HTTPS_PROXY"] = "http://USER:PASS@PROXY_HOST:PROXY_PORT"

client = genai.Client(
    api_key="YOUR_API_KEY",
    http_options=types.HttpOptions(
        timeout=60000,
        retry_options=types.HttpRetryOptions(attempts=1),
    ),
)
try:
    response = client.models.generate_content(
        model="gemini-flash-latest",
        contents="ping",
    )
    print(response.text)
finally:
    client.close()

That snippet talks to Google if you leave base_url unset. The loopback check did not. Ports in the saved results are dead. Copy host and port from a proxy that is still up.

  1. Call once with no proxy environment and no client_args proxy. Direct returned simulated text. The dummy CONNECT proxy stayed idle. proxy_events=0.
  2. Export HTTPS_PROXY to http://127.0.0.1:PROXY_PORT and call again. The proxy logged CONNECT 127.0.0.1:ORIGIN_PORT. The origin returned the same SIMULATED text. getproxies showed only the https key.
  3. Repeat with client_args={'proxy': 'http://127.0.0.1:PROXY_PORT'} and no HTTPS_PROXY. CONNECT happened again. Two doors, one tunnel type.
HTTPS_PROXY sent CONNECT on loopback and returned simulated generateContent text

A browser What is my IP page shows the browser exit. It does not show this Python process. The proxy checker tells you whether a host answers HTTP or SOCKS5. Useful before you paste an endpoint. Still not google-genai.

04Keep TLS on and keep credentials out of logs

HTTPS through an HTTP proxy is CONNECT, then TLS to the origin through that tunnel. The proxy URL stays http://.... An https:// proxy URL would mean TLS to the proxy itself. This run did not measure that.

The lab CA was a one-day certificate with a subject alternative name for 127.0.0.1. SSL_CERT_FILE pointed at that CA. Verification stayed on. When the same proxied client ran without SSL_CERT_FILE, CONNECT still succeeded and httpx raised ConnectError wrapping CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate. The hop was fine. The trust store was not. That is the case people skip, then they add verify=False and call it done.

CONNECT succeeded, then TLS failed without the lab CA
  1. Keep the default verify path. Pass a CA file only when your origin is private.
  2. Confirm CONNECT in the proxy log before you celebrate a TLS traceback. The traceback is not proof the proxy was skipped.
  3. Redact Proxy-Authorization, x-goog-api-key, and proxy userinfo. The lab proxy recorded has_proxy_authorization: false because the dummy hop had no Basic auth. Your vendor hop probably does.

Do not copy the lab CA into the system trust store. This run never touched macOS trust. SSL_CERT_FILE in the child process was enough.

05Tell a dead hop from a Google-looking error

Troubleshooting splits client SDK issues from backend issues. Retry 429 and 503. Do not retry 400, 402, or 403. Those are invalid keys, empty prepay credits, or bad syntax, not a flaky socket. None of that fires if TCP never completes.

This run forced three failures on the same installed client.

A closed loopback port as client_args proxy raised ConnectError: [Errno 61] Connection refused in 0.001s. No CONNECT log. The origin never saw a request. That is a dead hop.

A simulated origin 403 through a living CONNECT hop raised ClientError: 403 PERMISSION_DENIED with body text that said SIMULATED. CONNECT was logged. The origin counted a hit. Transport worked. The application refused. On real Google that class of error is account, billing, or policy. It is not "buy a different proxy and the model appears."

A 200ms HttpOptions.timeout against a 1.5s origin sleep raised ReadTimeout: The read operation timed out at 0.205s. CONNECT was logged. The tunnel was up. The budget was not.

Connection refused on a dead port versus simulated 403 after CONNECT
ObservationExceptionCONNECT loggedOrigin hitWhat to change
Direct, trusted lab CAnonenoyesControl. Proxy must stay idle
HTTPS_PROXY onlynoneyesyesRoute proven for this client
client_args proxynoneyesyesExplicit httpx proxy arg
Proxy up, no lab CAConnectError TLS issueryesnoFix CA. Do not disable verify
Dead proxy portConnectError refusednonoHost and port, not the API key
Simulated 403 through proxyClientError 403yesyesAccount or request. Hop already worked
200ms timeout, slow originReadTimeoutyesno finished bodyTimeout budget, not CONNECT

Mobile and datacenter catalog pages will not save you from that table. Mobile proxies and datacenter proxies change the IP you present. They do not rewrite google-genai error classes. HTTP is the protocol this SDK actually used. SOCKS5 stays a README extra until you install httpx[socks] and measure it.

06Match HTTP CONNECT to a catalog endpoint you can open

Pick a hop the vendor documents as HTTP, with username and password the vendor documents. Then prove google-genai against a fixture you own. Paid gateways were not called.

Oxylabs residential proxies, accessed 15 October 2026, document an HTTP entry. Decodo residential quick start, same day, documents gate.decodo.com:7000 as an HTTP proxy URL. The English catalog still lists that product as smartproxy-com. Compare those shapes on the live cards for Oxylabs and Smartproxy / Decodo. That is catalog fit, not a pool test.

  1. Match scheme to what 2.30.1 actually sent: HTTP CONNECT. An HTTPS-proxy-to-the-proxy URL is a different product.
  2. Put vendor prefixes on the proxy user, not on GEMINI_API_KEY.
  3. Check reachability with the proxy checker if you only need HTTP versus SOCKS on a host. Prove the SDK on your process.
Oxylabs — residential and datacenter proxies
Oxylabs — residential and datacenter proxies4.0770

Oxylabs sells residential, datacenter and mobile proxies. Residential self-serve starts at $6/GB for 5 GB/month. Buyer payments: cards, wire, AliPay, PayPal.

10 countries
$0.59
per 1 GB
Decodo (Smartproxy) — residential and datacenter proxies
Decodo (Smartproxy) — residential and datacenter proxies4.22106

Decodo (formerly Smartproxy) sells residential and datacenter proxies. Residential: $4/GB without a monthly plan, or monthly packs from $3.75/GB for 3 GB. Payments: cards, PayPal, Alipay, Google/Apple Pay, crypto (with limits).

83 countries
$0.38
per 1 GB
Compact executed result table from the loopback google-genai check

Make this client leave through a hop you can name, keep TLS on, and stop treating a tunnel as an entitlement.

How do I set a proxy for the Gemini Python SDK?

Export HTTPS_PROXY to an HTTP proxy URL before genai.Client, or pass HttpOptions.client_args={"proxy": "http://host:port"}. google-genai 2.30.1 uses httpx by default. Construct the client after the environment is set, then close it.

Does a working proxy mean Gemini will answer?

No. A CONNECT log proves the hop. Account, billing, quota, model, and the published region list are separate. Loopback SIMULATED JSON is not a Google result.

Should I turn TLS verification off?

No. This run left verify on. Without the lab CA, CONNECT still succeeded and the client raised ConnectError for a missing issuer. Fix the CA file. Do not disable verification.

Is SOCKS5 supported?

The SDK README says yes after pip install httpx[socks] and HttpOptions.client_args with a socks5 URL. This walkthrough did not install that extra and did not measure SOCKS.

Why did troubleshooting mention retries I did not see?

The 13 October 2026 troubleshooting page says the Python SDK retries transient errors up to four times. Installed 2.30.1 leaves retry_options unset, and that path stops after one attempt. Pass HttpRetryOptions if you want retries. Keep attempts at 1 while you debug a hop.

Can I use a browser What is my IP page to prove the SDK?

No. /en/my-ip shows the browser. google-genai is a separate process. Use a proxy log or an origin stamp from this client.