Connecting other libraries
BrowserQL is our first-class browser automation API, and includes powerful options like human-like, reconnecting and proxying. It's a full rethink of how to do browser automation with a minimalistic stealth-first approach. In order to get started, you'll need to sign-up for a cloud plan and get your API Key as well as our Desktop editor -- all of which are available via the account portal.
If you already have an automation library that works over WebSockets (like puppeteer or playwright), then you can mix-and-match BrowserQL with the library of your choice. This is perfect for getting past a nasty bot blockage and then connecting your existing scripts back.
Similarly, if you want to run more BrowserQL at a later time then you can do that as well.
Connecting A Library
Using "example.com" as a basis, you can run the following BrowserQL query then ask for a connection back:
mutation Reconnect {
goto(url: "https://example.com/", waitUntil: networkIdle) {
status
}
reconnect (timeout: 30000) {
browserWSEndpoint
}
}
The reconnect query has a timeout
argument, which is a limit (in milliseconds) for how long the browser should be available before it gets shutdown when nothing connects to it. If a connection were to happen after this time, a semantic 404
is returned back. When a connection happens, this will clear the timer and the session can continue past this limit.
Here are full examples using Puppeteer and Playwright:
- Puppeteer
- Playwright
import puppeteer from 'puppeteer-core';
const url = 'https://example.com';
const token = 'YOUR_API_TOKEN_HERE';
const timeout = 5 * 60 * 1000;
const queryParams = new URLSearchParams({
timeout,
token,
}).toString();
const query = `
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserWSEndpoint
}
}
`;
const variables = { url };
const endpoint =
`https://production-sfo.browserless.io/chromium/bql?${queryParams}`;
const options = {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
query,
variables,
}),
};
try {
console.log(`Running BQL Query: ${url}`);
const response = await fetch(endpoint, options);
if (!response.ok) {
throw new Error(`Got non-ok response:\n` + (await response.text()));
}
const { data } = await response.json();
const browserWSEndpoint = data.reconnect.browserWSEndpoint
console.log(`Got OK response! Connecting puppeteer to ${browserWSEndpoint}`);
const browser = await puppeteer.connect({
browserWSEndpoint,
});
console.log(`Connected to ${await browser.version()}`);
const pages = await browser.pages();
const page = pages.find((p) => p.url().includes(url));
await page.screenshot({ fullPage: true, path: 'temp.png' });
await browser.close();
} catch (error) {
console.error(error);
}
- Javascript
- Python
- Java
- C#
import playwright from 'playwright-core';
const url = 'https://example.com';
const token = 'YOUR_API_TOKEN_HERE';
const timeout = 5 * 60 * 1000;
const queryParams = new URLSearchParams({
timeout,
token,
}).toString();
const query = `
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserWSEndpoint
}
}
`;
const variables = { url };
const endpoint =
`https://production-sfo.browserless.io/playwright./bql?${queryParams}`;
const options = {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
query,
variables,
}),
};
(async () => {
try {
console.log(`Running BQL Query: ${url}`);
const response = await fetch(endpoint, options);
if (!response.ok) {
throw new Error(`Got non-ok response:\n` + (await response.text()));
}
const { data } = await response.json();
const browserWSEndpoint = data.reconnect.browserWSEndpoint;
console.log(`Got OK response! Connecting Playwright to ${browserWSEndpoint}`);
const browser = await playwright.chromium.connectOverCDP(browserWSEndpoint);
const context = browser.contexts()[0];
const page = context.pages().find((p) => p.url().includes(url));
if (!page) {
throw new Error(`Could not find a page matching ${url}`);
}
await page.screenshot({ fullPage: true, path: 'temp.png' });
await browser.close();
} catch (error) {
console.error(error);
}
})();
import requests
from playwright.sync_api import sync_playwright
url = "https://example.com"
token = "YOUR_API_TOKEN_HERE"
timeout = 5 * 60 * 1000
query_params = f"token={token}&timeout={timeout}"
endpoint = f"https://production-sfo.browserless.io/chromium/bql?{query_params}"
query = """
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserWSEndpoint
}
}
"""
variables = {"url": url}
headers = {"content-type": "application/json"}
body = {"query": query, "variables": variables}
try:
print(f"Running BQL Query: {url}")
response = requests.post(endpoint, json=body, headers=headers)
if response.status_code != 200:
raise Exception(f"Got non-ok response:\n{response.text}")
data = response.json().get("data")
browser_ws_endpoint = data["reconnect"]["browserWSEndpoint"]
print(f"Got OK response! Connecting Playwright to {browser_ws_endpoint}")
with sync_playwright() as playwright:
browser = playwright.chromium.connect_over_cdp(browser_ws_endpoint)
context = browser.contexts[0]
page = next((p for p in context.pages if url in p.url), None)
if not page:
raise Exception(f"Could not find a page matching {url}")
page.screenshot(path="temp.png", full_page=True)
browser.close()
except Exception as e:
print(f"Error: {e}")
package com.example;
import com.microsoft.playwright.*;
import com.google.gson.*;
import java.net.http.*;
import java.net.URI;
import java.util.*;
public class PlaywrightBQL {
public static void main(String[] args) {
String url = "https://example.com";
String token = "YOUR_API_TOKEN_HERE";
int timeout = 5 * 60 * 1000;
String queryParams = String.format("token=%s&timeout=%d", token, timeout);
String endpoint = String.format("https://production-sfo.browserless.io/chromium/bql?%s", queryParams);
String query = """
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserWSEndpoint
}
}
""";
JsonObject variables = new JsonObject();
variables.addProperty("url", url);
JsonObject body = new JsonObject();
body.addProperty("query", query);
body.add("variables", variables);
try {
// Send GraphQL request
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("Failed request: " + response.body());
}
// Parse response
JsonObject data = JsonParser.parseString(response.body()).getAsJsonObject().getAsJsonObject("data");
String browserWSEndpoint = data.getAsJsonObject("reconnect").get("browserWSEndpoint").getAsString();
System.out.println("Connecting Playwright to " + browserWSEndpoint);
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().connectOverCDP(browserWSEndpoint);
BrowserContext context = browser.contexts().get(0);
Page page = context.pages().stream()
.filter(p -> p.url().contains(url))
.findFirst()
.orElseThrow(() -> new RuntimeException("Page not found"));
page.screenshot(new Page.ScreenshotOptions().setPath("temp.png").setFullPage(true));
browser.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Playwright;
class Program
{
static async System.Threading.Tasks.Task Main(string[] args)
{
string url = "https://example.com";
string token = "YOUR_API_TOKEN_HERE";
int timeout = 5 * 60 * 1000;
string queryParams = $"token={token}&timeout={timeout}";
string endpoint = $"https://production-sfo.browserless.io/chromium/bql?{queryParams}";
string query = @"
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserWSEndpoint
}
}";
var body = new
{
query = query,
variables = new { url }
};
try
{
// Send GraphQL request
using var client = new HttpClient();
var requestContent = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
var response = await client.PostAsync(endpoint, requestContent);
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Request failed: {await response.Content.ReadAsStringAsync()}");
}
var jsonResponse = JsonNode.Parse(await response.Content.ReadAsStringAsync());
string browserWSEndpoint = jsonResponse["data"]["reconnect"]["browserWSEndpoint"].ToString();
Console.WriteLine($"Connecting Playwright to {browserWSEndpoint}");
// Connect to Playwright
using var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.ConnectOverCDPAsync(browserWSEndpoint);
var context = browser.Contexts[0];
var page = context.Pages.Find(p => p.Url.Contains(url)) ?? throw new Exception("Page not found");
// Take screenshot
await page.ScreenshotAsync(new PageScreenshotOptions { Path = "temp.png", FullPage = true });
await browser.CloseAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
Reconnecting with more BrowserQL
Similar to connecting a 3rd-party library, you can also reconnect back and execute more BrowserQL as well. BrowserQL does this by generating a new unique URL to use for running more queries. You can take this URL, append your API-token to it, and run more query language.
This is particularly useful for cases like AI where you might want to run several queries as users interact with your platform, but you don't want to necessarily keep an open connection.
Here are full examples running two BrowserQL queries on the same browser:
- Javascript
- Python
- Java
- C#
const url = 'https://example.com';
const token = 'YOUR_API_TOKEN_HERE';
const timeout = 5 * 60 * 1000;
const queryParams = new URLSearchParams({
timeout,
token,
}).toString();
const endpoint = `https://production-sfo.browserless.io/chromium/bql`;
const variables = { url };
const query = `
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserQLEndpoint
}
}
`;
const queryTwo = `
mutation GetText {
text {
text
}
}
`;
const bql = async (url, query, variables) => {
const data = await fetch(`${url}?${queryParams}`, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
query,
variables,
}),
});
if (!data.ok) {
throw new Error(`Non OK response: ${await data.text()}`);
}
return data.json();
};
try {
console.log(`Running BQL Query#1: ${url}`);
const first = await bql(endpoint, query, variables);
const browserQLEndpoint = first.data.reconnect.browserQLEndpoint;
console.log(`Running BQL Query#2: ${browserQLEndpoint}`);
const second = await bql(browserQLEndpoint, queryTwo);
console.log(`Got results: "${second.data.text.text}"`);
} catch (error) {
console.error(error);
}
import requests
url = "https://example.com"
token = "YOUR_API_TOKEN_HERE"
timeout = 5 * 60 * 1000
query_params = {
"timeout": timeout,
"token": token,
}
endpoint = "https://production-sfo.browserless.io/chromium/bql"
variables = {"url": url}
query_one = """
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserQLEndpoint
}
}
"""
query_two = """
mutation GetText {
text {
text
}
}
"""
def bql(endpoint_url, query, variables):
response = requests.post(
f"{endpoint_url}?timeout={query_params['timeout']}&token={query_params['token']}",
headers={"Content-Type": "application/json"},
json={"query": query, "variables": variables},
)
if not response.ok:
raise Exception(f"Non OK response: {response.text}")
return response.json()
try:
print(f"Running BQL Query#1: {url}")
first_response = bql(endpoint, query_one, variables)
browser_qle_endpoint = first_response["data"]["reconnect"]["browserQLEndpoint"]
print(f"Running BQL Query#2: {browser_qle_endpoint}")
second_response = bql(browser_qle_endpoint, query_two, {})
print(f'Got results: "{second_response["data"]["text"]["text"]}"')
except Exception as error:
print(f"Error: {error}")
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
public class BrowserlessBQL {
public static void main(String[] args) {
String url = "https://example.com";
String token = "YOUR_API_TOKEN_HERE";
int timeout = 5 * 60 * 1000;
String endpoint = "https://production-sfo.browserless.io/chromium/bql";
String queryOne = """
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserQLEndpoint
}
}
""";
String queryTwo = """
mutation GetText {
text {
text
}
}
""";
JsonObject variables = new JsonObject();
variables.addProperty("url", url);
try {
System.out.println("Running BQL Query#1...");
JsonObject firstResponse = runBQL(endpoint, queryOne, variables, token, timeout);
String browserQLEndpoint = firstResponse
.getAsJsonObject("data")
.getAsJsonObject("reconnect")
.get("browserQLEndpoint")
.getAsString();
System.out.println("Running BQL Query#2...");
JsonObject secondResponse = runBQL(browserQLEndpoint, queryTwo, new JsonObject(), token, timeout);
String text = secondResponse
.getAsJsonObject("data")
.getAsJsonObject("text")
.get("text")
.getAsString();
System.out.println("Got results: \"" + text + "\"");
} catch (Exception e) {
e.printStackTrace();
}
}
private static JsonObject runBQL(String endpoint, String query, JsonObject variables, String token, int timeout) throws Exception {
String queryParams = String.format("?timeout=%d&token=%s", timeout, token);
URL url = new URL(endpoint + queryParams);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
JsonObject payload = new JsonObject();
payload.addProperty("query", query);
payload.add("variables", variables);
try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
writer.write(payload.toString());
writer.flush();
}
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new RuntimeException("Non OK response: " + connection.getResponseMessage());
}
return JsonParser.parseReader(new java.io.InputStreamReader(connection.getInputStream())).getAsJsonObject();
}
}
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.Json;
class Program
{
static void Main(string[] args)
{
string url = "https://example.com";
string token = "YOUR_API_TOKEN_HERE";
int timeout = 5 * 60 * 1000;
string endpoint = "https://production-sfo.browserless.io/chromium/bql";
string queryOne = @"
mutation Reconnect($url: String!) {
goto(url: $url, waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserQLEndpoint
}
}
";
string queryTwo = @"
mutation GetText {
text {
text
}
}
";
var variables = new { url };
try
{
Console.WriteLine("Running BQL Query#1...");
var firstResponse = RunBQL(endpoint, queryOne, variables, token, timeout);
string browserQLEndpoint = firstResponse
.GetProperty("data")
.GetProperty("reconnect")
.GetProperty("browserQLEndpoint")
.GetString();
Console.WriteLine("Running BQL Query#2...");
var secondResponse = RunBQL(browserQLEndpoint, queryTwo, new { }, token, timeout);
string text = secondResponse
.GetProperty("data")
.GetProperty("text")
.GetProperty("text")
.GetString();
Console.WriteLine($"Got results: \"{text}\"");
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error: {ex.Message}");
}
}
static JsonElement RunBQL(string endpoint, string query, object variables, string token, int timeout)
{
string queryParams = $"?timeout={timeout}&token={token}";
var url = endpoint + queryParams;
var payload = new
{
query,
variables
};
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string jsonPayload = JsonSerializer.Serialize(payload);
streamWriter.Write(jsonPayload);
streamWriter.Flush();
}
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception($"Non OK response: {response.StatusDescription}");
}
using (var reader = new StreamReader(response.GetResponseStream()))
{
string result = reader.ReadToEnd();
return JsonSerializer.Deserialize<JsonElement>(result);
}
}
}
}