Change Your Browser's IP Address Using Proxies
Route browser traffic through a residential or datacenter proxy so target websites see a different IP. This is useful for geo-restricted content, rate-limit avoidance, and reducing bot-detection signals tied to datacenter ranges.
- A Browserless API token from your account dashboard
Steps
Add proxy=residential (or proxy=datacenter) and optionally proxyCountry to your connection URL. The example navigates to an IP-check page and returns the proxy IP to confirm routing is working.
proxy=datacenter— faster and cheaper (2 units/MB vs 6 units/MB for residential), but easier for sites to detectproxySticky=true— keep the same IP for the full browser sessionexternalProxyServer=http://user:pass@host:port— route through your own proxy server insteadproxyLocaleMatch=true— automatically set the browser locale to match the proxy country
- REST API
- Frameworks
- BQL
Add proxy parameters to the /scrape endpoint URL. Browserless handles proxy negotiation server-side, so your request looks identical to a normal scrape. Only the egress IP changes.
- cURL
- JavaScript
- Python
- Java
- C#
1. Send the request
curl -X POST \
"https://production-sfo.browserless.io/scrape?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.ipify.org?format=json",
"elements": [{ "selector": "body" }]
}'
2. Check the output
The text field contains the JSON response from ipify showing the proxy IP. Confirm it differs from your local or datacenter IP:
{
"data": [
{
"selector": "body",
"results": [
{
"text": "{\"ip\": \"203.0.113.42\"}",
"html": "{\"ip\": \"203.0.113.42\"}"
}
]
}
]
}
1. Send the request
const response = await fetch(
'https://production-sfo.browserless.io/scrape?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://api.ipify.org?format=json',
elements: [{ selector: 'body' }],
}),
}
);
const { data } = await response.json();
const ip = JSON.parse(data[0].results[0].text).ip;
console.log('Proxy IP:', ip);
2. Check the output
Run with node proxy.mjs. The logged IP is the residential proxy address, not the Browserless datacenter IP.
1. Install dependencies
pip install requests
2. Send the request
import requests
import json
response = requests.post(
'https://production-sfo.browserless.io/scrape',
params={
'token': 'YOUR_API_TOKEN_HERE',
'proxy': 'residential',
'proxyCountry': 'us',
},
json={
'url': 'https://api.ipify.org?format=json',
'elements': [{'selector': 'body'}],
},
)
data = response.json()['data']
ip = json.loads(data[0]['results'][0]['text'])['ip']
print('Proxy IP:', ip)
3. Check the output
Run with python proxy.py. The logged IP is the residential proxy address, not the Browserless datacenter IP.
1. Send the request
import java.net.URI;
import java.net.http.*;
String token = "YOUR_API_TOKEN_HERE";
String endpoint = "https://production-sfo.browserless.io/scrape?token=" + token
+ "&proxy=residential&proxyCountry=us";
String payload = "{\"url\": \"https://api.ipify.org?format=json\", \"elements\": [{\"selector\": \"body\"}]}";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
2. Check the output
Compile and run the class. The response JSON contains the proxy IP inside the body text field. Confirm it differs from your local or datacenter IP.
1. Send the request
using System.Net.Http;
using System.Text;
using System.Text.Json;
string token = "YOUR_API_TOKEN_HERE";
string endpoint = $"https://production-sfo.browserless.io/scrape?token={token}&proxy=residential&proxyCountry=us";
var payload = new
{
url = "https://api.ipify.org?format=json",
elements = new[] { new { selector = "body" } },
};
using (HttpClient httpClient = new HttpClient())
{
var content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(endpoint, content);
string body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}
2. Check the output
Run the program. The response body contains the proxy IP inside the body text field. Confirm it differs from your local or datacenter IP.
Add proxy parameters to the WebSocket connection URL. Because the parameters attach at the session level, every page opened in that browser instance exits through the same proxy. You don't need to configure proxies inside Puppeteer or Playwright separately.
- Puppeteer
- Playwright
1. Install dependencies
npm install puppeteer-core
2. Connect and check the IP
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint:
'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us',
});
try {
const page = await browser.newPage();
await page.goto('https://api.ipify.org?format=json', { waitUntil: 'networkidle2' });
const ip = await page.evaluate(() => JSON.parse(document.body.innerText).ip);
console.log('Proxy IP:', ip);
} finally {
await browser.close();
}
3. Check the output
Run with node proxy.mjs. The logged IP is the residential proxy address, not the Browserless datacenter IP.
1. Install dependencies
npm install playwright-core
2. Connect and check the IP
import { chromium } from 'playwright-core';
const browser = await chromium.connect(
'wss://production-sfo.browserless.io/chromium/playwright?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us'
);
try {
const page = await browser.newPage();
await page.goto('https://api.ipify.org?format=json', { waitUntil: 'networkidle' });
const ip = await page.evaluate(() => JSON.parse(document.body.innerText).ip);
console.log('Proxy IP:', ip);
} finally {
await browser.close();
}
3. Check the output
Run with node proxy.mjs. The logged IP is the residential proxy address, not the Browserless datacenter IP.
1. Write the mutation
Navigate to the IP-check endpoint and read the body text. Pass proxy parameters in the BQL endpoint URL query string. BQL itself has no proxy field, so the query string is the right place for them.
mutation CheckIP {
goto(url: "https://api.ipify.org?format=json", waitUntil: domContentLoaded) {
status
}
ip: innerText(selector: "body") {
innerText
}
}
2. Run it
Paste into the BQL IDE and click Run.
3. Check the output
{
"data": {
"goto": { "status": 200 },
"ip": { "innerText": "{\"ip\": \"203.0.113.42\"}" }
}
}
Next steps
- Solving Cloudflare Challenges — combine proxies with Cloudflare bypass for full bot-detection avoidance
- Scrape Etsy Product Listings — proxy-backed scraping of a real marketplace
- Solving reCAPTCHAs — use residential proxies to reduce CAPTCHA frequency