Skip to main content
Bruno provides powerful scripting capabilities through the Script component, allowing you to write JavaScript code that executes before sending requests (pre-request) or after receiving responses (post-response).

Overview

Scripts in Bruno are JavaScript code snippets that run in a sandboxed environment. They’re managed by the Script component in RequestPane/Script/index.js.

Script Types

Bruno supports two types of scripts:

Pre-Request Scripts

Execute before the request is sent. Use to set variables, modify headers, or prepare data.Accessed via the “Pre Request” tab in the Script pane.

Post-Response Scripts

Execute after receiving the response. Use to extract data, set variables, or chain requests.Accessed via the “Post Response” tab in the Script pane.

Script Editor

The Script component provides two CodeMirror editors:
  • Pre-request editor: preRequestEditorRef - Mode: javascript
  • Post-response editor: postResponseEditorRef - Mode: javascript
Both editors include:
  • Syntax highlighting for JavaScript
  • Auto-hints for req, res, and bru objects
  • Keyboard shortcuts (Cmd/Ctrl+Enter to run, Cmd/Ctrl+S to save)

Error Indicators

The Script tab shows status dots to indicate script state:
From Script component
<StatusDot type={item.preRequestScriptErrorMessage ? 'error' : 'default'} />
<StatusDot type={item.postResponseScriptErrorMessage ? 'error' : 'default'} />
Error status dots appear when a script fails execution, helping you quickly identify problematic scripts.

Pre-Request Scripts

Pre-request scripts execute before Bruno sends the HTTP request. They have access to the req and bru objects.

Available Objects

req
object
Request object with methods to modify the outgoing request:
  • req.setHeader(name, value): Set request header
  • req.getHeader(name): Get request header
  • req.setBody(data): Set request body
  • req.getUrl(): Get request URL
  • req.setUrl(url): Set request URL
bru
object
Bruno utility object:
  • bru.setVar(name, value): Set collection variable
  • bru.getVar(name): Get collection variable
  • bru.setEnvVar(name, value): Set environment variable
  • bru.getEnvVar(name): Get environment variable

Pre-Request Script Examples

// Set timestamp header
const timestamp = Date.now();
req.setHeader('X-Request-Timestamp', timestamp.toString());

// Set custom user agent
req.setHeader('User-Agent', 'Bruno/1.0 (Custom)');

Post-Response Scripts

Post-response scripts execute after receiving the API response. They have access to req, res, and bru objects.

Available Objects

res
object
Response object with response data:
  • res.status: HTTP status code
  • res.statusText: Status text (e.g., “OK”)
  • res.headers: Response headers object
  • res.body: Parsed response body
  • res.getHeader(name): Get specific header
  • res.getBody(): Get response body
req
object
Original request object (read-only in post-response)
bru
object
Bruno utility object (same as pre-request)

Post-Response Script Examples

From the test suite:
bruno-tests/collection/auth/bearer/via auth/Bearer Auth 200.bru
bru.setEnvVar("foo", "bar");
More complex example:
// Extract token from response
const accessToken = res.body.access_token;
const refreshToken = res.body.refresh_token;
const expiresIn = res.body.expires_in;

// Store in environment
bru.setEnvVar('access_token', accessToken);
bru.setEnvVar('refresh_token', refreshToken);

// Calculate expiry time
const expiryTime = Date.now() + (expiresIn * 1000);
bru.setEnvVar('token_expiry', expiryTime);

console.log(`Token stored, expires at ${new Date(expiryTime)}`);

Collection-Level Scripts

Scripts can be configured at the collection level in collection.bru, as shown in the test suite:
bruno-tests/collection/collection.bru
script:pre-request {
  // Collection-level pre-request script
  const shouldTestCollectionScripts = bru.getVar('should-test-collection-scripts');
  if(shouldTestCollectionScripts) {
   bru.setVar('collection-var-set-by-collection-script', 'collection-var-value-set-by-collection-script');
  }
}

tests {
  // Collection-level tests
  const shouldTestCollectionScripts = bru.getVar('should-test-collection-scripts');
  const collectionVar = bru.getVar("collection-var-set-by-collection-script");
  if (shouldTestCollectionScripts && collectionVar) {
    test("collection level test - should get the var that was set by the collection script", function() {
      expect(collectionVar).to.equal("collection-var-value-set-by-collection-script");
    }); 
    bru.setVar('collection-var-set-by-collection-script', null); 
    bru.setVar('should-test-collection-scripts', null);
  }
}
Collection-level scripts run for every request in the collection, unless overridden at the folder or request level.

Script Execution Order

When a request is sent, scripts execute in this order:
1

Collection Pre-Request Script

If configured in collection.bru, runs first.
2

Folder Pre-Request Script

If the request is in a folder with scripts, folder script runs next.
3

Request Pre-Request Script

Request-specific pre-request script runs last.
4

HTTP Request Sent

Bruno sends the request with all modifications applied.
5

Request Post-Response Script

Request-specific post-response script runs first.
6

Folder Post-Response Script

Folder post-response script runs next.
7

Collection Post-Response Script

Collection post-response script runs last.

Available Node.js Modules

Bruno scripts run in a sandboxed environment with access to common Node.js modules:
const encoded = require('btoa')('string to encode');
const decoded = require('atob')('encoded string');
The available modules depend on the bruno-js package configuration. Check packages/bruno-js for the complete list of bundled libraries.

Debugging Scripts

Console Logging

Use console.log() to debug scripts. Output appears in the response pane’s Console tab:
console.log('Pre-request script started');
console.log('Request URL:', req.getUrl());
console.log('API Key:', bru.getEnvVar('api_key'));

const timestamp = Date.now();
console.log('Timestamp:', timestamp);
req.setHeader('X-Timestamp', timestamp);

console.log('Pre-request script completed');

Error Handling

try {
  const token = res.body.access_token;
  if (!token) {
    throw new Error('Access token not found in response');
  }
  bru.setEnvVar('access_token', token);
  console.log('✓ Token extracted successfully');
} catch (error) {
  console.error('✗ Error:', error.message);
  console.error('Response body:', JSON.stringify(res.body));
}

Status Indicators

The Script tab shows error indicators:
Component behavior
{hasPreRequestScript && (
  <StatusDot type={item.preRequestScriptErrorMessage ? 'error' : 'default'} />
)}
{hasPostResponseScript && (
  <StatusDot type={item.postResponseScriptErrorMessage ? 'error' : 'default'} />
)}
Errors are stored in:
  • item.preRequestScriptErrorMessage
  • item.postResponseScriptErrorMessage

Common Patterns

Pre-Request Script
// Check if token is expired
const tokenExpiry = bru.getEnvVar('token_expiry');
const now = Date.now();

if (!tokenExpiry || now >= tokenExpiry) {
  console.log('Token expired, will need refresh');
  bru.setVar('needs_token_refresh', true);
}
Post-Response Script
// Store new token
if (res.body.access_token) {
  const expiresIn = res.body.expires_in || 3600;
  const expiry = Date.now() + (expiresIn * 1000);
  
  bru.setEnvVar('access_token', res.body.access_token);
  bru.setEnvVar('token_expiry', expiry);
  console.log('✓ Token refreshed');
}
// Generate HMAC signature
const crypto = require('crypto');
const secret = bru.getEnvVar('api_secret');
const timestamp = Date.now().toString();
const body = JSON.stringify(req.getBody());

const message = `${timestamp}.${body}`;
const signature = crypto
  .createHmac('sha256', secret)
  .update(message)
  .digest('hex');

req.setHeader('X-Timestamp', timestamp);
req.setHeader('X-Signature', signature);
// Modify request based on environment
const env = bru.getEnvVar('environment');

if (env === 'development') {
  // Use verbose mode in dev
  req.setHeader('X-Debug-Mode', 'true');
  console.log('Debug mode enabled');
} else if (env === 'production') {
  // Add production-specific headers
  req.setHeader('X-Production-Mode', 'true');
  req.setHeader('X-App-Version', bru.getVar('app_version'));
}
// Extract multiple values for request chaining
const { id, token, metadata } = res.body;

bru.setVar('resource_id', id);
bru.setVar('resource_token', token);
bru.setVar('resource_metadata', JSON.stringify(metadata));

console.log('Extracted data for next request:');
console.log('- ID:', id);
console.log('- Token:', token);
console.log('Next: Use {{resource_id}} in subsequent requests');

Best Practices

Scripts should be focused and easy to understand. Complex logic should be broken into multiple scripts or extracted to collection-level scripts.
Add console.log statements to track script execution and debug issues. Logs appear in the Response Console tab.
Wrap risky operations in try-catch blocks to prevent script failures from breaking your workflow.
Put common logic (auth token refresh, signature generation) in collection-level scripts to avoid duplication.
Store reusable values as variables. Use environment variables for environment-specific values and collection variables for runtime data.
Add comments to explain what the script does, especially for complex transformations or auth flows.

Script Storage

Scripts are stored in the .bru file format:
script:pre-request {
  // Pre-request script code
  const timestamp = Date.now();
  req.setHeader('X-Timestamp', timestamp);
}

script:post-response {
  // Post-response script code
  const token = res.body.access_token;
  bru.setEnvVar('access_token', token);
}
The Redux store manages draft scripts:
  • updateRequestScript: Updates pre-request script
  • updateResponseScript: Updates post-response script

Next Steps

Tests

Learn how to write test assertions

Collection Settings

Configure collection-level scripts

Environment Variables

Manage variables across environments

Authentication

Use scripts for dynamic authentication

Build docs developers (and LLMs) love