Skip to content

Scripting Recipes

Small, real scripts you can drop into a rule and tweak. Each one names which phase it goes in (request or response). For the full API surface, see the Scripting API Reference.

Phase: request. Match: https://api.example.com/*.

pro.request.headers.upsert({
key: 'X-Request-Id',
value: pro.crypto.sha256(Date.now() + ':' + Math.random()).slice(0, 16),
});

Adds a short hex trace ID to every outgoing request so server logs can be cross-referenced with what Probe captured.

Phase: request. Match: the API host that requires signing.

const ts = Math.floor(Date.now() / 1000).toString();
const body = pro.request.body.raw || '';
const secret = pro.environment.get('apiSecret');
const sig = pro.crypto.hmacSha256(ts + body, secret);
pro.request.headers.upsert({ key: 'X-Timestamp', value: ts });
pro.request.headers.upsert({ key: 'X-Signature', value: sig });

Signs the timestamp + body with a secret pulled from the environment, attaching both as headers.

Phase: request. Useful when you want to see who an outgoing call is authenticating as.

const auth = pro.request.headers.get('Authorization') || '';
const token = auth.replace(/^Bearer\s+/i, '');
if (token) {
const decoded = pro.crypto.jwtDecode(token);
console.log('sub:', decoded.payload.sub, 'exp:', decoded.payload.exp);
}

Logs the sub and exp claims of the bearer token to Probe’s scripting console.

Phase: response. Match: https://api.example.com/auth/login.

if (pro.response.code === 200) {
const token = pro.response.json().accessToken;
pro.environment.set('authToken', token);
console.log('captured authToken (' + token.length + ' chars)');
}

Pulls the accessToken out of the login response and stashes it in the active environment so later requests can reference it as {{authToken}}.

Phase: response. Match: the endpoint you’re testing.

pro.test('status is 200', function () {
pro.expect(pro.response.code).to.equal(200);
});
pro.test('content type is JSON', function () {
pro.expect(pro.response.headers.get('Content-Type')).to.contain('application/json');
});
pro.test('body has the right shape', function () {
pro.expect(pro.response.json()).to.have.jsonSchema({
type: 'object',
required: ['userId', 'email'],
properties: {
userId: { type: 'integer' },
email: { type: 'string' },
},
});
});

Three independent test blocks — failures in one don’t hide the others. Results show up in the scripting console with pass/fail badges.

Mock a 500 error for a percentage of requests

Section titled “Mock a 500 error for a percentage of requests”

Phase: request. Forces a percentage of calls to fail so you can exercise the client’s error path.

if (Math.random() < 0.2) {
// Reroute the upstream to an endpoint we know returns 500.
pro.request.url = 'https://httpstat.us/500';
console.warn('forcing 500 for testing');
}

20% of matching requests get rewritten to an upstream that always returns 500. To replace a response body in flight without going to a real origin, use Map Local instead.

Replace a JSON field in the response (via Map Local + script)

Section titled “Replace a JSON field in the response (via Map Local + script)”

For permanent response edits, Map Local is the right tool — it doesn’t even hit the network. But you can use a response script to log when the field is what you didn’t expect:

pro.test('user is admin', function () {
const data = pro.response.json();
pro.expect(data.user.role).to.equal('admin');
});

Pair this with a Map Local rule that serves the canned admin response, and the test confirms your client behaves correctly when the role flips.

Phase: request. Match: https://api.example.com/*.

const token = pro.environment.get('authToken');
const exp = parseInt(pro.environment.get('authExp') || '0', 10);
const nowSec = Math.floor(Date.now() / 1000);
if (!token || nowSec >= exp) {
const res = pro.sendRequest({
url: 'https://api.example.com/auth/refresh',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken: pro.environment.get('refreshToken') }),
});
if (res.code === 200) {
const body = res.json();
pro.environment.set('authToken', body.accessToken);
pro.environment.set('authExp', String(nowSec + body.expiresIn));
pro.request.headers.upsert({ key: 'Authorization', value: 'Bearer ' + body.accessToken });
} else {
console.error('refresh failed:', res.code, res.status);
}
}

Checks an expiry stored in the environment, calls the refresh endpoint synchronously via pro.sendRequest, then attaches the fresh token to the original request before it goes out. Up to 5 sub-requests per execution are allowed.

Phase: request. Useful when you want to test an unauthenticated path without logging out of the browser.

pro.request.headers.remove('Cookie');
pro.request.headers.remove('Authorization');

Removes the auth headers Probe captured from your browser session for just this rule’s matched requests.

Phase: response. Logs the server-reported response time only when it crosses a threshold.

if (pro.response.responseTime > 500) {
console.warn(
pro.info.requestName,
'took',
pro.response.responseTime + 'ms',
'(>' + 500 + 'ms threshold)',
);
}

Quiet most of the time, noisy when the endpoint is slow.