Search Automation
The click and type mutations let you interact with search bars, dismiss popups, and submit queries. BrowserQL uses level 4 CSS selectors and handles wait conditions automatically.
Basic Usage
The example below navigates to Booking.com, dismisses a sign-in modal, types a destination, and submits the search.
- BQL Query
- cURL
- Javascript
- Python
- Java
- C#
mutation SearchBooking {
goto(url: "https://www.booking.com", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: "button[aria-label='Dismiss sign-in info.']"
visible: true
timeout: 5000
) {
time
}
type(
text: "New York"
selector: "input[name='ss'][placeholder='Where are you going?']"
) {
selector
}
submitSearch: click(
selector: "button[type='submit']"
visible: true
) {
selector
time
}
}
curl --request POST \
--url 'https://production-sfo.browserless.io/chromium/bql?token=YOUR_API_TOKEN_HERE' \
--header 'Content-Type: application/json' \
--data '{"query":"mutation SearchBooking {\n goto(url: \"https://www.booking.com\", waitUntil: networkIdle) {\n status\n }\n\n closeModal: click(\n selector: \"button[aria-label='\''Dismiss sign-in info.'\'']\"\n visible: true\n timeout: 5000\n ) {\n time\n }\n\n type(\n text: \"New York\"\n selector: \"input[name='\''ss'\''][placeholder='\''Where are you going?'\'']\"\n ) {\n selector\n }\n\n submitSearch: click(\n selector: \"button[type='\''submit'\'']\"\n visible: true\n ) {\n selector\n time\n }\n}","variables":{},"operationName":"SearchBooking"}'
const endpoint = "https://production-sfo.browserless.io/chromium/bql";
const token = "YOUR_API_TOKEN_HERE";
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `mutation SearchBooking {
goto(url: "https://www.booking.com", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: "button[aria-label='Dismiss sign-in info.']"
visible: true
timeout: 5000
) {
time
}
type(
text: "New York"
selector: "input[name='ss'][placeholder='Where are you going?']"
) {
selector
}
submitSearch: click(
selector: "button[type='submit']"
visible: true
) {
selector
time
}
}`,
variables: "",
operationName: "SearchBooking",
})
};
const url = `${endpoint}?token=${token}`;
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
import requests
endpoint = "https://production-sfo.browserless.io/chromium/bql"
query_string = {
"token": "YOUR_API_TOKEN_HERE",
}
headers = {
"Content-Type": "application/json",
}
payload = {
"query": """mutation SearchBooking {
goto(url: "https://www.booking.com", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: "button[aria-label='Dismiss sign-in info.']"
visible: true
timeout: 5000
) {
time
}
type(
text: "New York"
selector: "input[name='ss'][placeholder='Where are you going?']"
) {
selector
}
submitSearch: click(
selector: "button[type='submit']"
visible: true
) {
selector
time
}
}""",
"variables": {},
"operationName": "SearchBooking",
}
response = requests.post(endpoint, params=query_string, headers=headers, json=payload)
print(response.json())
String url = "https://production-sfo.browserless.io/chromium/bql";
String token = "YOUR_API_TOKEN_HERE";
String endpoint = String.format("%s?token=%s", url, token);
HttpResponse<String> response = Unirest.post(endpoint)
.header("Content-Type", "application/json")
.body("{\"query\":\"mutation SearchBooking {\\n goto(url: \\\"https://www.booking.com\\\", waitUntil: networkIdle) {\\n status\\n }\\n\\n closeModal: click(\\n selector: \\\"button[aria-label='Dismiss sign-in info.']\\\",\\n visible: true,\\n timeout: 5000\\n ) {\\n time\\n }\\n\\n type(\\n text: \\\"New York\\\",\\n selector: \\\"input[name='ss'][placeholder='Where are you going?']\\\"\\n ) {\\n selector\\n }\\n\\n submitSearch: click(\\n selector: \\\"button[type='submit']\\\",\\n visible: true\\n ) {\\n selector\\n time\\n }\\n}\",\"variables\":\"\",\"operationName\":\"SearchBooking\"}")
.asString();
string url = "https://production-sfo.browserless.io/chromium/bql";
string token = "YOUR_API_TOKEN_HERE";
string endpoint = $"{url}?token={token}";
var payload = new
{
query = @"mutation SearchBooking {
goto(url: ""https://www.booking.com"", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: ""button[aria-label='Dismiss sign-in info.']""
visible: true
timeout: 5000
) {
time
}
type(
text: ""New York""
selector: ""input[name='ss'][placeholder='Where are you going?']""
) {
selector
}
submitSearch: click(
selector: ""button[type='submit']""
visible: true
) {
selector
time
}
}",
variables = "",
operationName = "SearchBooking"
};
using (HttpClient httpClient = new HttpClient())
{
var jsonPayload = System.Text.Json.JsonSerializer.Serialize(payload);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(endpoint, content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
Waiting for Search Results
After submitting a search, use waitForNavigation to pause until the results page loads, then extract the page HTML. See Wait Conditions for more options to wait.
- BQL Query
- cURL
- Javascript
- Python
- Java
- C#
mutation SearchAndExtract {
goto(url: "https://www.booking.com", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: "button[aria-label='Dismiss sign-in info.']"
visible: true
timeout: 5000
) {
time
}
type(
text: "New York"
selector: "input[name='ss'][placeholder='Where are you going?']"
) {
selector
}
submitSearch: click(
selector: "button[type='submit']"
visible: true
) {
selector
time
}
waitForNavigation {
time
}
html {
html
}
}
curl --request POST \
--url 'https://production-sfo.browserless.io/chromium/bql?token=YOUR_API_TOKEN_HERE' \
--header 'Content-Type: application/json' \
--data '{"query":"mutation SearchAndExtract {\n goto(url: \"https://www.booking.com\", waitUntil: networkIdle) {\n status\n }\n\n closeModal: click(\n selector: \"button[aria-label='\''Dismiss sign-in info.'\'']\"\n visible: true\n timeout: 5000\n ) {\n time\n }\n\n type(\n text: \"New York\"\n selector: \"input[name='\''ss'\''][placeholder='\''Where are you going?'\'']\"\n ) {\n selector\n }\n\n submitSearch: click(\n selector: \"button[type='\''submit'\'']\"\n visible: true\n ) {\n selector\n time\n }\n\n waitForNavigation {\n time\n }\n\n html {\n html\n }\n}","variables":{},"operationName":"SearchAndExtract"}'
const endpoint = "https://production-sfo.browserless.io/chromium/bql";
const token = "YOUR_API_TOKEN_HERE";
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `mutation SearchAndExtract {
goto(url: "https://www.booking.com", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: "button[aria-label='Dismiss sign-in info.']"
visible: true
timeout: 5000
) {
time
}
type(
text: "New York"
selector: "input[name='ss'][placeholder='Where are you going?']"
) {
selector
}
submitSearch: click(
selector: "button[type='submit']"
visible: true
) {
selector
time
}
waitForNavigation {
time
}
html {
html
}
}`,
variables: "",
operationName: "SearchAndExtract",
})
};
const url = `${endpoint}?token=${token}`;
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
import requests
endpoint = "https://production-sfo.browserless.io/chromium/bql"
query_string = {
"token": "YOUR_API_TOKEN_HERE",
}
headers = {
"Content-Type": "application/json",
}
payload = {
"query": """mutation SearchAndExtract {
goto(url: "https://www.booking.com", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: "button[aria-label='Dismiss sign-in info.']"
visible: true
timeout: 5000
) {
time
}
type(
text: "New York"
selector: "input[name='ss'][placeholder='Where are you going?']"
) {
selector
}
submitSearch: click(
selector: "button[type='submit']"
visible: true
) {
selector
time
}
waitForNavigation {
time
}
html {
html
}
}""",
"variables": {},
"operationName": "SearchAndExtract",
}
response = requests.post(endpoint, params=query_string, headers=headers, json=payload)
print(response.json())
String url = "https://production-sfo.browserless.io/chromium/bql";
String token = "YOUR_API_TOKEN_HERE";
String endpoint = String.format("%s?token=%s", url, token);
HttpResponse<String> response = Unirest.post(endpoint)
.header("Content-Type", "application/json")
.body("{\"query\":\"mutation SearchAndExtract {\\n goto(url: \\\"https://www.booking.com\\\", waitUntil: networkIdle) {\\n status\\n }\\n\\n closeModal: click(\\n selector: \\\"button[aria-label='Dismiss sign-in info.']\\\",\\n visible: true,\\n timeout: 5000\\n ) {\\n time\\n }\\n\\n type(\\n text: \\\"New York\\\",\\n selector: \\\"input[name='ss'][placeholder='Where are you going?']\\\"\\n ) {\\n selector\\n }\\n\\n submitSearch: click(\\n selector: \\\"button[type='submit']\\\",\\n visible: true\\n ) {\\n selector\\n time\\n }\\n\\n waitForNavigation {\\n time\\n }\\n\\n html {\\n html\\n }\\n}\",\"variables\":\"\",\"operationName\":\"SearchAndExtract\"}")
.asString();
string url = "https://production-sfo.browserless.io/chromium/bql";
string token = "YOUR_API_TOKEN_HERE";
string endpoint = $"{url}?token={token}";
var payload = new
{
query = @"mutation SearchAndExtract {
goto(url: ""https://www.booking.com"", waitUntil: networkIdle) {
status
}
closeModal: click(
selector: ""button[aria-label='Dismiss sign-in info.']""
visible: true
timeout: 5000
) {
time
}
type(
text: ""New York""
selector: ""input[name='ss'][placeholder='Where are you going?']""
) {
selector
}
submitSearch: click(
selector: ""button[type='submit']""
visible: true
) {
selector
time
}
waitForNavigation {
time
}
html {
html
}
}",
variables = "",
operationName = "SearchAndExtract"
};
using (HttpClient httpClient = new HttpClient())
{
var jsonPayload = System.Text.Json.JsonSerializer.Serialize(payload);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(endpoint, content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
Handling Conditional Elements
The if mutation runs its nested block only when a selector is present at the time of execution. Use it to interact with elements that appear conditionally, such as date pickers, banners, or upsell prompts.
if does not waitif evaluates the selector immediately. It does not wait for the element to appear. If the element loads asynchronously, add a waitForSelector call before the if block to ensure the element has time to render.
mutation ConditionalDatePicker {
goto(url: "https://www.booking.com", waitUntil: networkIdle) {
status
}
type(
text: "New York"
selector: "input[name='ss'][placeholder='Where are you going?']"
) {
selector
}
submitSearch: click(
selector: "button[type='submit']"
visible: true
) {
time
}
waitForNavigation {
time
}
ifDateFlexible: if(selector: "#flexible-searchboxdatepicker-tab-trigger", visible: true) {
clickFlexible: click(
selector: "#flexible-searchboxdatepicker-tab-trigger"
) {
time
}
}
html {
html
}
}
Use ifnot to run a block only when a selector is absent.