Puppeteer & Playwright
The reconnect mutation returns a WebSocket endpoint you can pass to Puppeteer or Playwright. This lets you use BQL for unblocking (solving CAPTCHAs, bypassing bot detection) and then hand off control to your library for everything else.
You can also reconnect to run more BQL queries instead of connecting a library. See the Reconnect to Browserless guide.
The Reconnect Mutation
Run your BQL mutations (navigation, unblocking, etc.) and call reconnect to get a browserWSEndpoint. This is the WebSocket URL you pass to Puppeteer's connect() or Playwright's connectOverCDP().
The timeout argument controls how long (in milliseconds) the browser waits for a library connection. If nothing connects within this window, the browser shuts down and returns a 404.
mutation Reconnect {
goto(url: "https://www.browserless.io/practice-form/", waitUntil: networkIdle) {
status
}
# Uncomment to solve Cloudflare before handing off:
# solve(type: cloudflare) {
# found
# solved
# time
# }
reconnect(timeout: 30000) {
browserWSEndpoint
}
}
Connecting with Libraries
The browserWSEndpoint from the response connects to any library that supports the Chrome DevTools Protocol (CDP). This includes Puppeteer (puppeteer.connect()) and Playwright (chromium.connectOverCDP()).
Execute your BQL query first, extract the browserWSEndpoint, then pass it to your library. The examples below navigate to a page with BQL, reconnect, and take a screenshot.
Connecting to Puppeteer
import puppeteer from 'puppeteer-core';
const url = 'https://www.browserless.io/practice-form';
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);
}
Connecting to Playwright
- JavaScript
- Python
- Java
- C#
import playwright from 'playwright-core';
const url = 'https://www.browserless.io/practice-form';
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,
}),
};
(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://www.browserless.io/practice-form"
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://www.browserless.io/practice-form";
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://www.browserless.io/practice-form";
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}");
}
}
}