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. Neither can be nested inside the other. Use sequential conditionals with compound selectors for multi-branch logic.
Conditions are evaluated immediately. if and ifnot do not wait for a selector to appear or a response to arrive. If the element isn't already on the page when the condition runs, it 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
}
}
}