Skip to content

Scripts

Every request can carry two kinds of script:

  • Pre-request script — runs before the request goes out. Mutate variables, sign a payload, decide a header.
  • Test script — runs after the response lands. Assert, extract, set environment variables.

Both run in an isolated QuickJS WASM sandbox. No DOM. No filesystem. No arbitrary network. Memory and execution time are capped.

Scripts use the native rs.* namespace. For drop-in Postman compatibility, pm is a live alias of the same object — rs.expect(...) and pm.expect(...) are identical, so existing Postman scripts run unchanged.

When you import a Postman collection, its pm.* calls are normalized to rs.* automatically; on export, they’re rewritten back to pm.* so the output still runs in Postman. (The rewrite only touches real pm./rs. identifiers — strings, comments, and regex literals are left intact.)

  • The API objectrs.request, rs.response, rs.environment, rs.globals, rs.collectionVariables, rs.variables, rs.test, rs.expect, rs.info, rs.iterationData.
  • chai-style assertionsrs.expect(rs.response.json().name).to.equal('alice').
  • JSON / text helpersrs.response.json(), rs.response.text(), rs.response.code, rs.response.responseTime.
  • rs.sendRequest(...) — fire an ad-hoc HTTP request from inside a script (routes through the same SSRF-guarded proxy as a normal request).
  • rs.vault — read/write an encrypted secret vault (await rs.vault.get('token')), so secrets stay out of variables and exports.
  • rs.cookies — read the cookie jar, plus an async rs.cookies.jar() for get/set/clear.
  • rs.execution — runner flow control: setNextRequest(name), skipRequest().
  • rs.visualizer.set(template, data) — render a custom HTML view of the response.
  • require(name) — a curated library set is bundled (see below).
  • Consoleconsole.log writes to the script output panel.
  • Legacy Postman globalspostman.setEnvironmentVariable(...) and friends, plus the old tests["label"] = true object style, both still work for scripts written before the pm.* API existed. New scripts should prefer rs.* / pm.*.

Full Postman v12 sandbox parity ships a fixed library set you can require — no arbitrary npm, but the common ones are there:

ajv · chai · cheerio · crypto-js · csv-parse/sync · lodash · moment · postman-collection · tv4 · uuid · xml2js

const CryptoJS = require('crypto-js');
const sig = CryptoJS.HmacSHA256(rs.request.body, rs.environment.get('secret')).toString();
rs.variables.set('signature', sig);
  • Raw fetch / XMLHttpRequest — there’s no bare network primitive; use rs.sendRequest(...) instead.
  • Arbitrary require / import — only the bundled library set above loads; no reaching into npm or your machine.
  • DOM globals and the filesystem.

These limits are deliberate: collections are often shared, and a script in a downloaded collection should never be able to exfiltrate data or reach into your machine. Memory and execution-time caps mean a runaway loop can’t take down the app.

rs.test('status is 200', () => {
rs.expect(rs.response.code).to.equal(200);
});
const body = rs.response.json();
rs.test('returns a user id', () => {
rs.expect(body.id).to.be.a('string');
});
// stash the id for the next request in this collection
rs.environment.set('user_id', body.id);
const ts = Math.floor(Date.now() / 1000);
rs.variables.set('signed_at', ts.toString());
// fetch a token first, then attach it
const res = await rs.sendRequest({
url: 'https://api.example.com/login',
method: 'POST',
headers: { 'content-type': 'application/json' },
body: { user: 'demo', pass: rs.environment.get('pass') },
});
rs.environment.set('token', res.body.token);