Conditional Logic in BQL
if and ifnot are BrowserQL mutations that execute nested operations based on a condition. if runs its body when the condition matches; ifnot runs its body when it does not.
- A Browserless API token from your account dashboard
- Familiarity with BQL language basics
if and ifnot do not wait for a selector to appear or a response to arrive, so an element not already on the page evaluates as not present. Use waitForSelector or waitForResponse before your conditional if timing matters.
Arguments
| Argument | Type | Available on | Description |
|---|---|---|---|
selector | String | if, ifnot | Triggers if the CSS selector matches an element on the page. |
visible | Boolean | if only | When using selector, requires the element to be visible in the viewport. Defaults to false. |
response | ResponseInput | if, ifnot | Triggers based on HTTP response status codes or URL pattern. |
request | RequestInput | if, ifnot | Triggers based on a matching HTTP request. |
ResponseInput fields:
statuses: [Int]: one or more HTTP status codes to matchurl: String: glob-style URL pattern to match the response URL
RequestInput fields:
method: Method: HTTP verb to match (GET,POST,PUT,DELETE,PATCH, and others)url: String: glob-style URL pattern to match the request URL
If a condition is not met, the branch returns null and execution continues. A skipped condition is not an error.
For the full schema, see the API reference.
Element Presence Conditions
Check if a selector is present on the page and run different operations depending on the result. Because if and ifnot are evaluated independently and in sequence, you can chain them to cover multiple branches in a single mutation. A common pattern is checking for a CAPTCHA before proceeding: if one is found, solve it and continue; if not, extract content directly:
mutation HandleCaptcha {
goto(url: "https://www.google.com/recaptcha/api2/demo") {
status
}
# No CAPTCHA - extract content directly
ifnot(selector: ".g-recaptcha") {
html {
html
}
}
# CAPTCHA detected - solve it before proceeding
if(selector: ".g-recaptcha") {
solve {
time
found
solved
}
click(selector: "#recaptcha-demo-submit") {
time
}
waitForNavigation {
time
}
html {
html
}
}
}
Visible Elements
By default, selector matches any element in the DOM, including those hidden with CSS. Add visible: true to if to require the element to also be rendered and visible in the viewport. This is useful for elements like modals, error messages, or menus that exist in the DOM before they are shown:
mutation VisibleElementCheck {
goto(url: "https://practicetestautomation.com/practice-test-login/") {
status
}
# Only fires if #error is in the DOM and visible — not just present but hidden
if(selector: "#error", visible: true) {
text(selector: "#error") {
text
}
}
}
Response Code Conditions
One of the most common uses is handling different HTTP response codes.
mutation ResponseHandling {
goto(url: "https://quotes.toscrape.com/doesntexist") {
status
}
# 4xx means access was denied or the resource wasn't found — capture the text and redirect
ifError4xx: if(response: {statuses: [400, 401, 403, 404]}) {
text {
text
}
goto(url: "https://quotes.toscrape.com") {
status
}
}
# Successful response — extract the main content
ifnot(response: {statuses: [400, 401, 403, 404, 500, 502, 503]}) {
html(selector: ".col-md-8") {
html
}
}
}
Request Conditions
request triggers based on HTTP requests the page has made. Use url to match a glob-style URL pattern, method to match an HTTP verb, or both together:
mutation RequestCondition {
goto(url: "https://jsonplaceholder.typicode.com/posts/1") {
status
}
# Fires if a GET request to the posts endpoint was made
if(request: {method: GET, url: "**/posts/**"}) {
text(selector: "body") {
text
}
}
# No matching request detected — take a screenshot for debugging
ifnot(request: {method: GET, url: "**/posts/**"}) {
screenshot {
base64
}
}
}
FAQ & Troubleshooting
My if condition isn't matching even though the element is on the page
if evaluates immediately and does not wait for elements to appear. Add a waitForSelector mutation before your conditional to ensure the element is in the DOM when the condition runs.
Can I nest if inside ifnot or vice versa?
No. if and ifnot cannot be nested inside each other. Use sequential conditionals with compound CSS selectors for multi-branch logic instead.