Go (playwright-go)
playwright-go is the community-maintained Go port of Playwright. It supports the same ConnectOverCDP method the other Playwright SDKs use, so connecting to Browserless works the same way. Point it at a wss:// endpoint with your API token as a query parameter. For available connection parameters, see connection URL patterns.
- A Browserless API token from your account dashboard
- Go with the
playwright-gopackage installed (go get github.com/playwright-community/playwright-go)
Basic usage
The example below connects to Browserless, navigates to example.com, and prints the page title:
package main
import (
"fmt"
"log"
"github.com/playwright-community/playwright-go"
)
const token = "YOUR_API_TOKEN_HERE" // Replace with your actual token.
func main() {
pw, err := playwright.Run()
if err != nil {
log.Fatalf("could not start playwright: %v", err)
}
defer pw.Stop()
// Connect to Browserless over CDP.
browser, err := pw.Chromium.ConnectOverCDP(
fmt.Sprintf("wss://production-sfo.browserless.io?token=%s", token),
)
if err != nil {
log.Fatalf("could not connect to browserless: %v", err)
}
defer browser.Close()
page, err := browser.NewPage()
if err != nil {
log.Fatalf("could not create page: %v", err)
}
if _, err = page.Goto("https://www.example.com/"); err != nil {
log.Fatalf("could not navigate: %v", err)
}
title, err := page.Title()
if err != nil {
log.Fatalf("could not get title: %v", err)
}
fmt.Printf("The page's title is: %s\n", title)
}
Output
The page's title is: Example Domain
Using an external proxy
When you pass an external proxy URL as a query parameter, any special characters in the credentials (like @, :, or #) need to be percent-encoded or the URL parser will misinterpret them. In Go, use url.QueryEscape for this:
package main
import (
"fmt"
"log"
"net/url"
"github.com/playwright-community/playwright-go"
)
const (
token = "YOUR_API_TOKEN_HERE"
proxyHost = "proxy.example.com"
proxyPort = "8080"
proxyUser = "username"
proxyPass = "p@ssw0rd#123" // Special chars that need encoding.
)
func main() {
pw, err := playwright.Run()
if err != nil {
log.Fatalf("could not start playwright: %v", err)
}
defer pw.Stop()
// Build and encode the proxy URL so special characters don't break the query string.
proxyURL := fmt.Sprintf("http://%s:%s@%s:%s", proxyUser, proxyPass, proxyHost, proxyPort)
encodedProxy := url.QueryEscape(proxyURL)
wsEndpoint := fmt.Sprintf(
"wss://production-sfo.browserless.io?token=%s&externalProxyServer=%s",
token,
encodedProxy,
)
browser, err := pw.Chromium.ConnectOverCDP(wsEndpoint)
if err != nil {
log.Fatalf("could not connect: %v", err)
}
defer browser.Close()
page, err := browser.NewPage()
if err != nil {
log.Fatalf("could not create page: %v", err)
}
if _, err = page.Goto("https://httpbin.org/ip"); err != nil {
log.Fatalf("could not navigate: %v", err)
}
body, err := page.Locator("body").TextContent()
if err != nil {
log.Fatalf("could not read body: %v", err)
}
fmt.Println(body)
}
Output
{
"origin": "proxy-ip-here"
}
For more proxy options (built-in residential/datacenter proxies, context-level proxy config), see Proxies.
Stealth mode
To bypass bot detection, swap the base path to /stealth (or /chromium/stealth). Everything else stays the same:
wsEndpoint := fmt.Sprintf(
"wss://production-sfo.browserless.io/stealth?token=%s",
token,
)
You can combine stealth with any other query parameters:
wsEndpoint := fmt.Sprintf(
"wss://production-sfo.browserless.io/stealth?token=%s&externalProxyServer=%s&timeout=300000",
token,
encodedProxy,
)
See Stealth Routes for the full list of stealth options.
Passing launch parameters
launch parameters and Browserless-specific options go directly in the query string. Because fmt.Sprintf builds a plain string, you can append as many parameters as you need:
wsEndpoint := fmt.Sprintf(
"wss://production-sfo.browserless.io?token=%s&--window-size=1920,1080&blockAds=true&timeout=60000",
token,
)
For the full list of available parameters, see launch parameters.
Go-specific tips
- Always call
url.QueryEscapeon values that contain special characters before inserting them into the query string. Go'sfmt.Sprintfdoes no escaping on its own, so unencoded@or#characters will corrupt the URL. - Use
defer browser.Close()to make sure the remote browser is released even if your program panics or returns early. Leaked sessions count against your concurrency limit. ConnectOverCDPvsConnect:ConnectOverCDPuses the Chrome DevTools Protocol and is the recommended method for Browserless.Connectuses Playwright's native protocol, which requires a Playwright-specific server and won't work with Browserless endpoints. Stick withConnectOverCDP.
Related docs
- Connection URL patterns – endpoint construction and query parameters
launchparameters – browser flags and Browserless-specific settings- Proxies – built-in and external proxy configuration
- Stealth Routes – bot detection bypass
- Session management – reconnection and persistent sessions
- Playwright customizations – advanced Playwright configuration
FAQ & Troubleshooting
Why am I getting a 403 Forbidden error?
Your API token is missing or expired. Pass it as a ?token= query parameter in the WebSocket or HTTP URL. Verify the token in your account dashboard.
My script works locally but fails on Browserless
Local browser settings may differ from the Browserless environment. Use launch parameters to match your local setup (viewport, user agent, timezone). See launch parameters for the full list.