Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions examples/batch-dom-queries/bql/batch-dom-queries.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Runs multiple DOM queries in a single BQL request.
# All fields execute in the same browser session — no repeated page loads.
mutation BatchDOMQueries {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}

title {
title
}

heading: text(selector: "h1") {
text
}

description: attribute(selector: "meta[name='description']", name: "content") {
value
}

links: mapSelector(selector: "a") {
text: innerText
href: attribute(name: "href") {
value
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Runs multiple DOM queries in a single browser session using Playwright.
//
// Install: npm install playwright-core
// Run: node batch-dom-queries.mjs

import { chromium } from 'playwright-core';

const TOKEN = 'YOUR_API_TOKEN_HERE';

const browser = await chromium.connectOverCDP(
`wss://production-sfo.browserless.io?token=${TOKEN}`
);

try {
const context = browser.contexts()[0] ?? await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });

// Run all queries in a single evaluate call to minimise round-trips.
const results = await page.evaluate(() => ({
title: document.title,
heading: document.querySelector('h1')?.innerText ?? '',
description: document.querySelector('meta[name="description"]')?.content ?? '',
links: Array.from(document.querySelectorAll('a')).map((a) => ({
text: a.innerText.trim(),
href: a.href,
})),
}));

console.log('Title:', results.title);
console.log('H1:', results.heading);
console.log('Description:', results.description);
console.log('Links:', results.links);
} finally {
await browser.close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Runs multiple DOM queries in a single browser session using Puppeteer.
//
// Install: npm install puppeteer-core
// Run: node batch-dom-queries.mjs

import puppeteer from 'puppeteer-core';

const TOKEN = 'YOUR_API_TOKEN_HERE';

const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io?token=${TOKEN}`,
});

try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });

// Run all queries in a single evaluate call to minimise round-trips.
const results = await page.evaluate(() => ({
title: document.title,
heading: document.querySelector('h1')?.innerText ?? '',
description: document.querySelector('meta[name="description"]')?.content ?? '',
links: Array.from(document.querySelectorAll('a')).map((a) => ({
text: a.innerText.trim(),
href: a.href,
})),
}));

console.log('Title:', results.title);
console.log('H1:', results.heading);
console.log('Description:', results.description);
console.log('Links:', results.links);
} finally {
await browser.close();
}
35 changes: 35 additions & 0 deletions examples/batch-dom-queries/rest/csharp/BatchDOMQueries.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Runs multiple DOM queries in a single BQL request.
//
// Run: dotnet run

using System.Net.Http;
using System.Text;
using System.Text.Json;

string token = "YOUR_API_TOKEN_HERE";
string endpoint = $"https://production-sfo.browserless.io/bql?token={token}";

var payload = new
{
query = @"mutation BatchDOMQueries {
goto(url: ""https://example.com"", waitUntil: networkIdle) { status }
title { title }
heading: text(selector: ""h1"") { text }
description: attribute(selector: ""meta[name='description']"", name: ""content"") { value }
links: mapSelector(selector: ""a"") {
text: innerText
href: attribute(name: ""href"") { value }
}
}",
variables = new { },
operationName = "BatchDOMQueries",
};

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);
}
12 changes: 12 additions & 0 deletions examples/batch-dom-queries/rest/curl/batch-dom-queries.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# Runs multiple DOM queries in a single BQL request — title, h1, meta description, and links.
# Run: bash batch-dom-queries.sh

curl -X POST \
"https://production-sfo.browserless.io/bql?token=YOUR_API_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation BatchDOMQueries { goto(url: \"https://example.com\", waitUntil: networkIdle) { status } title { title } heading: text(selector: \"h1\") { text } description: attribute(selector: \"meta[name='\''description'\'']\", name: \"content\") { value } links: mapSelector(selector: \"a\") { text: innerText href: attribute(name: \"href\") { value } } }",
"variables": {},
"operationName": "BatchDOMQueries"
}'
33 changes: 33 additions & 0 deletions examples/batch-dom-queries/rest/java/BatchDOMQueries.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Runs multiple DOM queries in a single BQL request.
//
// Run: javac BatchDOMQueries.java && java BatchDOMQueries

import java.net.URI;
import java.net.http.*;

public class BatchDOMQueries {
public static void main(String[] args) throws Exception {
String token = "YOUR_API_TOKEN_HERE";
String endpoint = "https://production-sfo.browserless.io/bql?token=" + token;

String query = "mutation BatchDOMQueries {"
+ " goto(url: \\\"https://example.com\\\", waitUntil: networkIdle) { status }"
+ " title { title }"
+ " heading: text(selector: \\\"h1\\\") { text }"
+ " description: attribute(selector: \\\"meta[name='description']\\\", name: \\\"content\\\") { value }"
+ " links: mapSelector(selector: \\\"a\\\") { text: innerText href: attribute(name: \\\"href\\\") { value } }"
+ " }";

String payload = "{\"query\": \"" + query + "\", \"variables\": {}, \"operationName\": \"BatchDOMQueries\"}";

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());
}
}
40 changes: 40 additions & 0 deletions examples/batch-dom-queries/rest/nodejs/batch-dom-queries.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Runs multiple DOM queries in a single BQL request — title, h1, meta description, and links.
// BQL executes all fields in one browser session, avoiding multiple round-trips.
//
// Run: node batch-dom-queries.mjs

const query = `mutation BatchDOMQueries {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
title {
title
}
heading: text(selector: "h1") {
text
}
description: attribute(selector: "meta[name='description']", name: "content") {
value
}
links: mapSelector(selector: "a") {
text: innerText
href: attribute(name: "href") {
value
}
}
}`;

const response = await fetch(
'https://production-sfo.browserless.io/bql?token=YOUR_API_TOKEN_HERE',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables: {}, operationName: 'BatchDOMQueries' }),
}
);

const { data } = await response.json();
console.log('Title:', data.title.title);
console.log('H1:', data.heading.text);
console.log('Description:', data.description.value);
console.log('Links:', data.links.map((l) => ({ text: l.text, href: l.href?.value })));
43 changes: 43 additions & 0 deletions examples/batch-dom-queries/rest/python/batch_dom_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Runs multiple DOM queries in a single BQL request — title, h1, meta description, and links.
# BQL executes all fields in one browser session, avoiding multiple round-trips.
#
# Install: pip install requests
# Run: python batch_dom_queries.py

import requests

query = """
mutation BatchDOMQueries {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
title {
title
}
heading: text(selector: "h1") {
text
}
description: attribute(selector: "meta[name='description']", name: "content") {
value
}
links: mapSelector(selector: "a") {
text: innerText
href: attribute(name: "href") {
value
}
}
}
"""

response = requests.post(
'https://production-sfo.browserless.io/bql',
params={'token': 'YOUR_API_TOKEN_HERE'},
json={'query': query, 'variables': {}, 'operationName': 'BatchDOMQueries'},
)

data = response.json()['data']
print('Title:', data['title']['title'])
print('H1:', data['heading']['text'])
print('Description:', data['description']['value'])
for link in data['links']:
print(f" {link['text']} -> {link['href']['value'] if link['href'] else ''}")
10 changes: 10 additions & 0 deletions examples/close-session/bql/close-session.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# BQL sessions are automatically closed when the mutation completes.
# For Session API sessions using BQL, terminate them with a DELETE request to the stop URL.
mutation CloseExample {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
text(selector: "h1") {
text
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Connects to Browserless via Playwright, does work, then closes the session.
//
// Install: npm install playwright-core
// Run: node close-session.mjs

import { chromium } from "playwright-core";

const TOKEN = "YOUR_API_TOKEN_HERE";
const browser = await chromium.connectOverCDP(
`wss://production-sfo.browserless.io?token=${TOKEN}&stealth`
);

try {
const context = browser.contexts()[0] ?? await browser.newContext();
const page = await context.newPage();
await page.goto("https://example.com", { waitUntil: "networkidle" });

const title = await page.title();
console.log("Page title:", title);
} finally {
await browser.close();
console.log("Browser closed — session resources released.");
}
22 changes: 22 additions & 0 deletions examples/close-session/frameworks/puppeteer/close-session.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Connects to Browserless via Puppeteer, does work, then closes the session.
//
// Install: npm install puppeteer-core
// Run: node close-session.mjs

import puppeteer from "puppeteer-core";

const TOKEN = "YOUR_API_TOKEN_HERE";
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io?token=${TOKEN}`,
});

try {
const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: "networkidle2" });

const title = await page.title();
console.log("Page title:", title);
} finally {
await browser.close();
console.log("Browser closed — session resources released.");
}
29 changes: 29 additions & 0 deletions examples/close-session/rest/csharp/CloseSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Creates a Browserless session and closes it via the Session API.
//
// Run: dotnet run

using System.Net.Http;
using System.Text;
using System.Text.Json;

var token = "YOUR_API_TOKEN_HERE";
var client = new HttpClient();

var content = new StringContent(
JsonSerializer.Serialize(new { ttl = 60000, stealth = true }),
Encoding.UTF8,
"application/json"
);

var response = await client.PostAsync(
$"https://production-sfo.browserless.io/session?token={token}",
content
);
var body = await response.Content.ReadAsStringAsync();
var session = JsonSerializer.Deserialize<JsonElement>(body);

var stopUrl = session.GetProperty("stop").GetString();
Console.WriteLine($"Session created: {session.GetProperty("id")}");

var closeResponse = await client.DeleteAsync($"{stopUrl}&force=true");
Console.WriteLine($"Session closed: {closeResponse.StatusCode}");
18 changes: 18 additions & 0 deletions examples/close-session/rest/curl/close-session.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Creates a Browserless session and immediately closes it.
# Run: bash close-session.sh

TOKEN="YOUR_API_TOKEN_HERE"

# Step 1: Create a session
SESSION=$(curl -s -X POST \
"https://production-sfo.browserless.io/session?token=${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"ttl": 60000, "stealth": true}')

echo "Session created: $SESSION"

# Step 2: Extract the stop URL and close the session
STOP_URL=$(echo "$SESSION" | python3 -c "import sys,json; print(json.load(sys.stdin)['stop'])")
curl -X DELETE "${STOP_URL}&force=true"
echo "Session closed."
Loading