Form Submission
The type, click, select, checkbox, and solve mutations let you fill, submit, and bypass CAPTCHAs in forms. BrowserQL handles element waiting, scrolling, and human-like input timing automatically.
Basic Usage
The example below navigates to a form, fills two fields, selects a dropdown option, and solves a CAPTCHA before submitting. For explicit control over timing, see Waiting for Things.
- BQL Query
- cURL
- Javascript
- Python
- Java
- C#
mutation FormExample {
goto(url: "https://www.browserless.io/practice-form") {
status
}
typeEmail: type(text: "john@email.com", selector: "#Email") {
time
}
typeMessage: type(
selector: "#Message"
text: "Watching BrowserQL do cool things!"
) {
time
}
subject: select(selector: "select#Subject", value: "Support") {
selector
}
solve {
time
solved
}
}
curl --request POST \
--url 'https://production-sfo.browserless.io/chromium/bql?token=YOUR_API_TOKEN_HERE' \
--header 'Content-Type: application/json' \
--data '{"query":"mutation FormExample {\n goto(url: \"https://www.browserless.io/practice-form\") {\n status\n }\n\n typeEmail: type(text: \"john@email.com\", selector: \"#Email\") {\n time\n }\n\n typeMessage: type(\n selector: \"#Message\"\n text: \"Watching BrowserQL do cool things!\"\n ) {\n time\n }\n\n subject: select(selector: \"select#Subject\", value: \"Support\") {\n selector\n }\n\n solve {\n time\n solved\n }\n}","variables":{},"operationName":"FormExample"}'
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 FormExample {
goto(url: "https://www.browserless.io/practice-form") {
status
}
typeEmail: type(text: "john@email.com", selector: "#Email") {
time
}
typeMessage: type(
selector: "#Message"
text: "Watching BrowserQL do cool things!"
) {
time
}
subject: select(selector: "select#Subject", value: "Support") {
selector
}
solve {
time
solved
}
}`,
variables: "",
operationName: "FormExample",
})
};
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 FormExample {
goto(url: "https://www.browserless.io/practice-form") {
status
}
typeEmail: type(text: "john@email.com", selector: "#Email") {
time
}
typeMessage: type(
selector: "#Message"
text: "Watching BrowserQL do cool things!"
) {
time
}
subject: select(selector: "select#Subject", value: "Support") {
selector
}
solve {
time
solved
}
}""",
"variables": {},
"operationName": "FormExample",
}
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 FormExample {\\n goto(url: \\\"https://www.browserless.io/practice-form\\\") {\\n status\\n }\\n\\n typeEmail: type(text: \\\"john@email.com\\\", selector: \\\"#Email\\\") {\\n time\\n }\\n\\n typeMessage: type(\\n selector: \\\"#Message\\\"\\n text: \\\"Watching BrowserQL do cool things!\\\"\\n ) {\\n time\\n }\\n\\n subject: select(selector: \\\"select#Subject\\\", value: \\\"Support\\\") {\\n selector\\n }\\n\\n solve {\\n time\\n solved\\n }\\n}\",\"variables\":\"\",\"operationName\":\"FormExample\"}")
.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 FormExample {
goto(url: ""https://www.browserless.io/practice-form"") {
status
}
typeEmail: type(text: ""john@email.com"", selector: ""#Email"") {
time
}
typeMessage: type(
selector: ""#Message""
text: ""Watching BrowserQL do cool things!""
) {
time
}
subject: select(selector: ""select#Subject"", value: ""Support"") {
selector
}
solve {
time
solved
}
}",
variables = "",
operationName = "FormExample"
};
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);
}
Deep Selectors for Iframes and Shadow DOM
Deep selectors target elements inside iframes or shadow DOMs. Add < at the start of any selector to enable deep traversal.
selector: "< [optional URL pattern] css-selector"
<signals a deep selector.- URL pattern (optional) matches the iframe source URL with glob syntax.
- CSS selector identifies the target element inside the matched frame.
- Iframe by URL glob
- Iframe by path
- Any iframe
- Exact iframe URL
Target a button inside any iframe from cnn.com:
selector: "< *cnn.com* button#submit"
Click an anchor inside a Google verification iframe:
selector: "< *google.com/api/verify* a[class*='now']"
Find an element with a price attribute across all iframes and the top-level page:
selector: "< [price]"
Find a span inside an iframe at an exact URL:
selector: "< https://amazon.com/ span.submit.order"
- Parent-child combinators (e.g.,
div > span) are not supported in deep selectors. - Each deep selector must target a single node.
Humanized Typing and Clicking
BrowserQL types with randomized delays between keystrokes to mimic human behavior. Two ways to control this:
Query parameter: Add humanlike=true to the connection URL to enable human-like behavior globally for the session.
Per-mutation delay: Set a delay range on the type mutation to control keystroke timing explicitly.
mutation HumanizedForm {
goto(url: "https://www.browserless.io/practice-form") {
status
}
# Randomize keystroke delay between 80ms and 200ms
typeMessage: type(
selector: "#Message"
text: "Hello, this looks human!"
delay: [80, 200]
) {
time
}
}
For session-level configuration, see Session Settings.