Skip to main content
Before your App code runs, Bruno injects a global window.bru into the guest page. All interaction with Bruno happens through bru.ctx.
Instead of using fetch() directly, your App calls bru.ctx.submitRequest() or bru.ctx.runRequest(). Bruno then interpolates variables, runs pre/post scripts, executes assertions and tests, records the timeline, and updates the response pane — exactly as if you pressed Send.
bru.ctx data arrives asynchronously after page load. Reading bru.ctx.http.response, bru.ctx.variables.resolved, or any other state field at the top level or inside DOMContentLoaded returns null or empty values.Always do the first render inside bru.ctx.onInit. React to later changes via the on*Change callbacks.

Shared surface

These fields and methods are available in both request-level and collection-level Apps.

Reading theme

Reading variables

Setting a runtime variable


Request-level App

These fields are only available on request-level Apps. They do not exist on collection Apps.

Sending the parent request

The request must reference {{userId}} in its URL, body, params, or headers. Bruno interpolates the variable — it does not search-and-replace literal strings.

Reacting to responses

Reading test results


Collection-level App

These fields are only available on collection-level Apps. They do not exist on request Apps.

Listing requests

Running a specific request


Types

Response

RequestSummary

Assertion

Test


Overrides

Both submitRequest and runRequest accept an optional options object:
How overrides work:
  • Values are injected as ephemeral runtime variables for that single send only.
  • They take precedence over all other variable scopes (global env, active env, collection vars, persistent runtime vars).
  • The request must reference them using {{name}} syntax — Bruno interpolates the variable at runtime. Hard-coded literal strings in the request body are not matched or replaced.
  • Overrides do not persist. To persist a value across requests, use bru.ctx.variables.runtime.set(name, value).

Notes & gotchas

bru.ctx.theme is an object, not a string. Use bru.ctx.theme.mode for the light/dark switch. The mode is also mirrored as a light / dark class on document.body. onInit receives bru, not ctx. The callback signature is (bru) => void. Access all state as bru.ctx.* inside it.
Overrides are nested under runtimeVariables. Flat top-level keys on the options object are ignored.
Pathnames are absolute filesystem paths. listRequests returns paths like /Users/me/collections/myapi/users/get-user.bru. They are stable as long as the file is not moved or renamed. No bru.ctx.http or bru.ctx.submitRequest on collection Apps. Those fields are request-level only. Accessing them on a collection App returns undefined. No bru.ctx.listRequests or bru.ctx.runRequest on request Apps. Those methods are collection-level only. Variable precedence. bru.ctx.variables.runtime.set and runtimeVariables overrides both write to the runtime scope, which sits at the top of Bruno’s precedence chain: global env → active env → collection vars → runtime vars.