JMeter Correlation: Handling Session Tokens and Dynamic Values
How to extract and reuse dynamic values like session tokens, CSRF tokens, and IDs in JMeter so recorded scripts work correctly under load.
Record a login flow with JMeter’s HTTP(S) Test Script Recorder and replay it, and it will usually fail the second request onward. The reason is correlation: the server returned a dynamic value (session ID, CSRF token, order ID) during recording that the script replays as a hardcoded, now-stale string. Every serious JMeter script needs correlation for any value the server generates per-session or per-request.
Spotting what needs correlation
Common candidates: session/auth tokens, CSRF tokens embedded in forms, view-state-style hidden fields, IDs returned from a “create” call and needed by a subsequent “read/update” call, and any URL parameter that changes between recording runs. A practical test: record the same flow twice and diff the two scripts — values that differ between the two recordings almost always need correlation.
Extracting values: the three main approaches
- Regular Expression Extractor — works on any text response, most flexible, slightly more fragile to format changes.
- CSS/JQuery Extractor — convenient for HTML responses, selecting elements by CSS selector.
- JSON Extractor (JSON Path) — the right tool for JSON APIs; far more robust than regex against a JSON body since it doesn’t care about whitespace or key order.
Each extractor is attached as a child of the sampler whose response contains the value, and stores the result into a JMeter variable for later samplers to reference as ${variableName}.
A concrete example
Say a login response includes "sessionToken":"abc123" in its JSON body. A JSON Extractor with JSON Path $.sessionToken and reference name sessionToken stores abc123 into ${sessionToken}. Any later sampler that needs to send this token (as a header or query parameter) references ${sessionToken} instead of the hardcoded value the recorder captured.
Handling values that don’t exist yet on failure
Set a Default Value on the extractor. If extraction fails (the pattern didn’t match), the variable falls back to that default rather than silently carrying over a stale value from a previous iteration — which can mask a real upstream failure by making it look like the test “passed” with wrong data.
Multiple matches
If a pattern could match more than once in a response, the extractor’s Match No. field controls which occurrence to use (0 for a random match, a positive number for a specific one, -1 to capture all matches into indexed variables for later iteration).
Debug efficiently
Add a Debug Sampler with a View Results Tree (while scripting only) to inspect exactly what variables were extracted and their values — far faster than guessing from a failing downstream request.
Takeaway: correlation isn’t optional polish — an uncorrelated script doesn’t measure your system under load, it mostly measures how quickly your system rejects malformed, stale requests. Treat every dynamic value as a correlation candidate until proven otherwise.
Comments are powered by Giscus (GitHub Discussions). Enable them by
configuring GISCUS in src/consts.ts — see
giscus.app.