Our Residential Proxy
Currently, Browserless V2 is available in production via two domains: production-sfo.browserless.io
and production-lon.browserless.io
Browserless offers a built-in residential proxy for paid cloud-unit accounts. You can sign-up for one here.
In order to effectively use this proxy, you'll need to adjust your code or API calls to let browserless proxy the request for you. For both library connect and REST API calls, the process is the same!
For strict bot detectors where browsers and a proxy aren't enough to get past, we would recommend using BrowserQL.
Puppeteer
The following uses our built-in residential proxy, targeting a node in the US:
import puppeteer from "puppeteer-core";
const TOKEN = "YOUR_API_TOKEN_HERE";
// Simply add proxy=residential and (optionally) a country
const browserWSEndpoint =
`wss://production-sfo.browserless.io?token=${TOKEN}&proxy=residential&proxyCountry=us`;
const url = "https://ipinfo.io/";
let browser;
try {
browser = await puppeteer.connect({ browserWSEndpoint });
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
await page.goto(url);
await page.screenshot({ path: "ip.png" });
} catch (e) {
console.log("Error during script:", e.message);
} finally {
browser && browser.close();
}
By default, all requests will go through a random node in the proxy pool. This may not be desireable and can cause other issues. In order to keep your session "sticky" (use the same IP node), add a proxySticky
parameter:
"http://production-sfo.browserless.io/content?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us&proxySticky";
Playwright
Our proxy service is also available for Playwright browsers. You only need to set the same parameters as for Puppeteer.
- Javascript
- Python
- Java
- C#
import playwright from "playwright-core";
const TOKEN = "YOUR_API_TOKEN_HERE"
// Simply add proxy=residential and (optionally) a country
const pwEndpoint = `wss://production-sfo.browserless.io/firefox/playwright?token=${TOKEN}&proxy=residential&proxyCountry=us`;
const browser = await playwright.firefox.connect(pwEndpoint);
const context = await browser.newContext();
const page = await context.newPage();
await page.goto("https://ipinfo.io/");
await page.screenshot({
path: `firefox.png`,
});
await browser.close();
from playwright.sync_api import sync_playwright
TOKEN = "YOUR_API_TOKEN_HERE"
pw_endpoint = f"wss://production-sfo.browserless.io/firefox/playwright?token={TOKEN}&proxy=residential&proxyCountry=us"
with sync_playwright() as p:
# Connect to the Browserless endpoint
browser = p.firefox.connect_over_cdp(pw_endpoint)
context = browser.new_context()
page = context.new_page()
# Navigate to the URL and take a screenshot
page.goto("https://ipinfo.io/")
page.screenshot(path="firefox.png")
# Close the browser connection
browser.close()
print("Screenshot saved as firefox.png")
import com.microsoft.playwright.*;
public class PlaywrightRemoteProxy {
public static void main(String[] args) {
String TOKEN = "YOUR_API_TOKEN_HERE";
String PW_ENDPOINT = "wss://production-sfo.browserless.io/firefox/playwright?token="
+ TOKEN + "&proxy=residential&proxyCountry=us";
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.firefox().connect(PW_ENDPOINT);
System.out.println("Connected to remote Firefox browser");
BrowserContext context = browser.newContext();
Page page = context.newPage();
page.navigate("https://ipinfo.io/");
page.screenshot(new Page.ScreenshotOptions().setPath("firefox.png"));
System.out.println("Screenshot saved as firefox.png");
browser.close();
}
}
}
using System;
using System.Threading.Tasks;
using Microsoft.Playwright;
class Program {
static async Task Main(string[] args) {
string TOKEN = "YOUR_API_TOKEN_HERE";
string PW_ENDPOINT = $"wss://production-sfo.browserless.io/firefox/playwright?token={TOKEN}&proxy=residential&proxyCountry=us";
var playwright = await Playwright.CreateAsync();
var browser = await playwright.Firefox.ConnectAsync(PW_ENDPOINT);
Console.WriteLine("Connected to remote Firefox browser");
var context = await browser.NewContextAsync();
var page = await context.NewPageAsync();
await page.GotoAsync("https://ipinfo.io/");
await page.ScreenshotAsync(new PageScreenshotOptions { Path = "firefox.png" });
Console.WriteLine("Screenshot saved as firefox.png");
await browser.CloseAsync();
}
}
By default, all requests will go through a random node in the proxy pool. This may not be desireable and can cause other issues. In order to keep your session "sticky" (use the same IP node), add a proxySticky
parameter:
"http://production-sfo.browserless.io/content?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us&proxySticky";
REST APIs
All of our REST-APIs function the same for proxying: simply add the proxy parameters you care about to the requests' query-string parameters, and you're all done. No need for credentials or otherwise.
Here's an examples of collecting content, pdf and screenshot from a United States Proxy:
Content
- cURL
- Javascript
- Python
- Java
- C#
curl --request POST \
--url "https://production-sfo.browserless.io/content?token=YOUR_API_TOKEN_HERE&proxyCountry=us&proxy=residential" \
--header "Content-Type: application/json" \
--data "{
"url": "https://ipinfo.io/"
}" \
--output "ipinfo.html"
import fetch from 'node-fetch';
import { writeFile } from 'fs/promises';
const TOKEN = "YOUR_API_TOKEN_HERE";
const url = `https://production-sfo.browserless.io/content?token=${TOKEN}&proxyCountry=us&proxy=residential`;
const headers = {
"Content-Type": "application/json"
};
const data = {
url: "https://ipinfo.io/"
};
const fetchContent = async () => {
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
const html = await response.text();
await writeFile("ipinfo.html", html);
console.log("HTML content saved as ipinfo.html");
};
fetchContent();
import requests
TOKEN = "YOUR_API_TOKEN_HERE"
url = f"https://production-sfo.browserless.io/content?token={TOKEN}&proxyCountry=us&proxy=residential"
headers = {
"Content-Type": "application/json"
}
data = {
"url": "https://ipinfo.io/"
}
response = requests.post(url, headers=headers, json=data)
with open("ipinfo.html", "wb") as f:
f.write(response.content)
print("HTML content saved as ipinfo.html")
import java.io.*;
import java.net.http.*;
import java.net.URI;
public class FetchHTML {
public static void main(String[] args) {
String TOKEN = "YOUR_API_TOKEN_HERE";
String url = "https://production-sfo.browserless.io/content?token=" + TOKEN + "&proxyCountry=us&proxy=residential";
HttpClient client = HttpClient.newHttpClient();
String jsonData = """
{
"url": "https://ipinfo.io/"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
try {
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
try (FileOutputStream fos = new FileOutputStream("ipinfo.html")) {
response.body().transferTo(fos);
System.out.println("HTML content saved to ipinfo.html");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program {
static async Task Main(string[] args) {
string TOKEN = "YOUR_API_TOKEN_HERE";
string url = $"https://production-sfo.browserless.io/content?token={TOKEN}&proxyCountry=us&proxy=residential";
var payload = new {
url = "https://ipinfo.io/"
};
var jsonContent = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
using var httpClient = new HttpClient();
try {
var response = await httpClient.PostAsync(url, jsonContent);
response.EnsureSuccessStatusCode();
var contentStream = await response.Content.ReadAsStreamAsync();
using (var fileStream = new FileStream("ipinfo.html", FileMode.Create, FileAccess.Write, FileShare.None)) {
await contentStream.CopyToAsync(fileStream);
Console.WriteLine("HTML content saved to ipinfo.html");
}
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
}
}
}
PDF
- cURL
- Javascript
- Python
- Java
- C#
curl --request POST \
--url "https://production-sfo.browserless.io/pdf?token=YOUR_API_TOKEN_HERE&proxyCountry=us&proxy=residential" \
--header "Content-Type: application/json" \
--data "{
\"url\": \"https://ipinfo.io/\"
}" \
--output "ipinfo.pdf"
import fetch from 'node-fetch';
import { writeFile } from 'fs/promises';
const TOKEN = "YOUR_API_TOKEN_HERE";
const url = `https://production-sfo.browserless.io/pdf?token=${TOKEN}&proxyCountry=us&proxy=residential`;
const headers = {
"Content-Type": "application/json"
};
const data = {
url: "https://ipinfo.io/"
};
const fetchPDF = async () => {
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
const pdfBuffer = await response.arrayBuffer();
await writeFile("ipinfo.pdf", Buffer.from(pdfBuffer));
console.log("PDF content saved as ipinfo.pdf");
};
fetchPDF();
import requests
TOKEN = "YOUR_API_TOKEN_HERE"
url = f"https://production-sfo.browserless.io/pdf?token={TOKEN}&proxyCountry=us&proxy=residential"
headers = {
"Content-Type": "application/json"
}
data = {
"url": "https://ipinfo.io/"
}
response = requests.post(url, headers=headers, json=data)
with open("ipinfo.pdf", "wb") as f:
f.write(response.content)
print("PDF content saved as ipinfo.pdf")
import java.io.*;
import java.net.http.*;
import java.net.URI;
public class FetchPDF {
public static void main(String[] args) {
String TOKEN = "YOUR_API_TOKEN_HERE";
String url = "https://production-sfo.browserless.io/pdf?token=" + TOKEN + "&proxyCountry=us&proxy=residential";
HttpClient client = HttpClient.newHttpClient();
String jsonData = """
{
"url": "https://ipinfo.io/"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
try {
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
try (FileOutputStream fos = new FileOutputStream("ipinfo.pdf")) {
response.body().transferTo(fos);
System.out.println("PDF saved as ipinfo.pdf");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program {
static async Task Main(string[] args) {
string TOKEN = "YOUR_API_TOKEN_HERE";
string url = $"https://production-sfo.browserless.io/pdf?token={TOKEN}&proxyCountry=us&proxy=residential";
var payload = new {
url = "https://ipinfo.io/"
};
var jsonContent = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
using var httpClient = new HttpClient();
try {
var response = await httpClient.PostAsync(url, jsonContent);
response.EnsureSuccessStatusCode();
var contentStream = await response.Content.ReadAsStreamAsync();
using (var fileStream = new FileStream("ipinfo.pdf", FileMode.Create, FileAccess.Write, FileShare.None)) {
await contentStream.CopyToAsync(fileStream);
Console.WriteLine("PDF saved as ipinfo.pdf");
}
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
}
}
}
Screenshot
- cURL
- Javascript
- Python
- Java
- C#
curl --request POST \
--url "https://production-sfo.browserless.io/screenshot?token=YOUR_API_TOKEN_HERE&proxyCountry=us&proxy=residential" \
--header "Content-Type: application/json" \
--data "{
\"url\": \"https://ipinfo.io/\"
}" \
--output "ipinfo.png"
import fetch from 'node-fetch';
import { writeFile } from 'fs/promises';
const TOKEN = "YOUR_API_TOKEN_HERE";
const url = `https://production-sfo.browserless.io/screenshot?token=${TOKEN}&proxyCountry=us&proxy=residential`;
const headers = {
"Content-Type": "application/json"
};
const data = {
url: "https://ipinfo.io/"
};
const fetchScreenshot = async () => {
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
const imageBuffer = await response.arrayBuffer();
await writeFile("ipinfo.png", Buffer.from(imageBuffer));
console.log("Screenshot saved as ipinfo.png");
};
fetchScreenshot();
import requests
TOKEN = "YOUR_API_TOKEN_HERE"
url = f"https://production-sfo.browserless.io/screenshot?token={TOKEN}&proxyCountry=us&proxy=residential"
headers = {
"Content-Type": "application/json"
}
data = {
"url": "https://ipinfo.io/"
}
response = requests.post(url, headers=headers, json=data)
with open("ipinfo.png", "wb") as f:
f.write(response.content)
print("Screenshot saved as ipinfo.png")
import java.io.*;
import java.net.http.*;
import java.net.URI;
public class FetchScreenshot {
public static void main(String[] args) {
String TOKEN = "YOUR_API_TOKEN_HERE";
String url = "https://production-sfo.browserless.io/screenshot?token=" + TOKEN + "&proxyCountry=us&proxy=residential";
HttpClient client = HttpClient.newHttpClient();
String jsonData = """
{
"url": "https://ipinfo.io/"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
try {
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
try (FileOutputStream fos = new FileOutputStream("ipinfo.png")) {
response.body().transferTo(fos);
System.out.println("Screenshot saved as ipinfo.png");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program {
static async Task Main(string[] args) {
string TOKEN = "YOUR_API_TOKEN_HERE";
string url = $"https://production-sfo.browserless.io/screenshot?token={TOKEN}&proxyCountry=us&proxy=residential";
var payload = new {
url = "https://ipinfo.io/"
};
var jsonContent = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
using var httpClient = new HttpClient();
try {
var response = await httpClient.PostAsync(url, jsonContent);
response.EnsureSuccessStatusCode();
var contentStream = await response.Content.ReadAsStreamAsync();
using (var fileStream = new FileStream("ipinfo.png", FileMode.Create, FileAccess.Write, FileShare.None)) {
await contentStream.CopyToAsync(fileStream);
Console.WriteLine("Screenshot saved as ipinfo.png");
}
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
}
}
}
By default, all requests will go through a random node in the proxy pool. This may not be desireable and can cause other issues. In order to keep your session "sticky" (use the same IP node), add a proxySticky
parameter:
"http://production-sfo.browserless.io/content?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us&proxySticky";
All proxy options
Today, we support only residential proxying in our paid cloud-unit plans. In the near future we'll expand this to Dedicated accounts as well as other proxy types. Below is a list of all query parameters and their options:
&proxy=residential
: Indicates which proxy type to use. Must be set, and as of today, the only option is residential.&proxyCountry=US
: An ISO 3166-1 two-digit country code. Defaults tous
or United States.&proxySticky
: When present, force all of chrome's network traffic to go through the same IP.
Be sure to refer to this document as we add more options in the future!
Cost
Never worry about topping up or buying more time. When you have a paid cloud-unit plan with us, you're simply charged 6 units per MB of traffic. For instance, a site that is 1MB would equate to using 6 units of cloud-unit plans, or roughly $0.01. Since our technology doesn't interrupt Chrome's requests, you can also instrument chrome (via puppeteer or our REST APIs) to reject requests that are unnecessary, like images and videos. See our other documentation pages for how to do that.
The other cost to consider is time. Using a residential proxy forces Chrome to issue requests through a residential (or consumer computer) proxy, meaning requests might be slower and thus take longer to resolve. You'll likely want to increase your timeout setting 5 - 10x what you might consider normal to allow traffic to flow properly.
Higher tier plans also come with the benefit of less cost per unit, meaning the more units you sign-up for the cheaper the proxying becomes. Our account page shows the amount of units used for proxying to give you an idea of how much is being spent on proxy-related costs.
FAQ
How come I'm getting a ERR_TUNNEL_CONNECTION_FAILED
?
There's two reasons this might happen. The first, and most rare, is a bad node or IP that's no longer working. Simply retry your requests and things should work properly.
The second is that some sites are blocked either by legal action. Unfortunately few providers can work around issues like these as they can be legally held responsible. Simply try your request without the proxy, or find a provider you'd like to use as we also allow 3rd party proxies as well.
I'm using Selenium/Webdriver but it's not working.
As of this time we currently don't have support for proxying in Selenium or other webdriver-based integrations (Capybara and more). We apologize for the inconvenience.
I'm using a lot of units on proxying, why is that?
When you launch Chrome with a proxy, it'll use that proxy for every request it makes. Puppeteer and other libraries come with handy network-request rejection APIs that can tell chrome not to make those requests if it's for an image, css, or even JavaScript. To do that is pretty simple:
// Abort image requests as they're big and not necessary most of time.
await page.on("request", (req) => {
if (!req.isInterceptResolutionHandled() && req.resourceType() === "image") {
return req.abort();
}
});
For most REST-based APIs you can do similarly by adding a payload property:
{
"url": "https://example.com",
"rejectResourceTypes": ["image"]
}
The site is really slow with the proxy, why?
When using residential proxies, Chrome makes many network "hops" in order to route traffic through that IP address. Depending on where you're running your code, and what country you target for proxying, this can mean multiple trips around the globe multiple times for every network request.
Fundamentally you can only do so much to make the speed of light faster! In cases like these where speed is important it's best to use a Dedicated plan to get infrastructure closer to where you intend to route traffic as well as increase timeouts where possible.