Correlation & Extractors
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. |
The reference material consulted while preparing these pages is listed in the section bibliography.
This page was written against Apache JMeter 5.6.3 (latest release on 2026-10-14; it runs on Java 8 and later, Java 17 or
later is recommended), with the differences planned for JMeter 6.0 noted where they matter. JMeter 6.0 is not
released: the planned changes come from xdocs/changes.xml on the master branch, need Java 17 or later (Java 21
recommended) and are described as planned, not as shipped behaviour. Every extractor on this page ships with core
JMeter, so no plugin is needed: the old jp@gc JSON Path Extractor plugin that the books use has been replaced by the
core JSON Extractor (3.0), JSON JMESPath Extractor (5.2) and Boundary Extractor (4.0). Field names, menu paths and
behaviour come from the official component reference and the regular expressions chapter of the user manual. Where the
manual is silent about which variables an extractor sets, the page says what the 5.6.3 source code does and names the
class it was read from.
A test plan that replays the same requests with the same values works for one user, once. Real APIs hand out values
that change on every call: a login returns a fresh JWT, POST /api/loans returns the id of a loan that did not exist a
second ago, an HTML form carries a CSRF token valid for one session. Correlation is the work of capturing such a
value from one response and sending it in a later request. JMeter does it with extractors, post-processors that read
a response and write JMeter variables. This page explains how to find the values to correlate, every extractor and all
its fields, exactly which variables each one creates (the -1 / _matchNr rules differ between them), and the
supporting techniques: defaults that make failures visible, ForEach loops over all matches, the regular expression
syntax and the Debug elements. It ends with the Bookshelf example: the login token and the new loan id.
It builds on Properties, Variables & Functions (how variables work) and Test Plan Elements, Execution Order & Scoping (where post-processors run), and pairs with HTTP Sessions, Headers, Cookies & Authentication, Recording & cURL Import and Assertions.
What correlation is
A dynamic value is any value in a request that the server generated, or that depends on server state, and that is therefore different for every user, session or iteration. In a REST or web application the usual ones are:
| Kind | Bookshelf example | Where it appears |
|---|---|---|
Authentication token (JWT, opaque bearer token) |
|
Response body; sent back in an |
Created resource id |
The new loan’s |
Response body and often the |
Selected item id |
A |
Response body (a list); sent back in a URL path |
CSRF / anti-forgery token |
A hidden |
HTML body or a cookie; sent back as a form field or header |
Session id |
A |
|
Pagination cursor, ETag, version number |
An |
Response header or body; sent back in a request header or body |
Without correlation a recorded plan sends the token, ids and CSRF values that existed when it was recorded. The requests then fail (401, 403, 404, 409) or, worse, succeed against the same single record for every virtual user, which measures a cache rather than the system. A load test whose requests do not do the real work is not a load test.
Cookies are the exception: the HTTP Cookie Manager stores Set-Cookie values per thread and sends them back
automatically, so session cookies need no extractor. Extractors are needed for every value that travels in a body,
a URL or a custom header.
Finding the values to correlate
Three techniques find correlation candidates, and they work best together.
Compare two recordings. Record the same journey twice, ideally with two different users, with the HTTP(S) Test
Script Recorder (see Recording & cURL Import). Save each as a
.jmx file and compare them with any diff tool. Values that differ between the two recordings in the same request
are dynamic: tokens, ids, timestamps, nonces. Values that are identical are either constants or data that should come
from a CSV file (see Parameterization & Test Data). Then, for
each dynamic value, find the earliest response that contains it: that response is where the extractor goes.
Search in the View Results Tree. Run one user (Thread Group with 1 thread, 1 loop, or the Validate command) with a View Results Tree listener (Add → Listener → View Results Tree). Take the dynamic value from a request that failed and type it into the listener’s Search field: the listener highlights every sample and response that contains it, so the first response holding the value is found in seconds. The component reference notes that this search uses the Java regular expression engine, not the ORO engine of the Regular Expression Extractor, and that it searches the visible text, so the Text and HTML views can give different results.
Read the API contract. For an API described by OpenAPI or a GraphQL schema, the dynamic fields are documented: the
login response schema has a token, the create-loan response has an id. The contract is faster than any diff.
The View Results Tree also has a renderer per extractor type, chosen from the drop-down at the bottom of its left
panel, to try an expression against a real response before putting it in the plan: Regexp Tester, CSS/JQuery
Tester, XPath Tester (and XPath2 Tester), JSON Path Tester, JSON JMESPath Tester and Boundary Extractor
Tester. The Regexp Tester uses the same engine as the Regular Expression Extractor and prints every match with its
groups, as Match[1][0] for the whole first match and Match[1][1] for its first group.
The View Results Tree keeps responses in memory and must not be used during a load test (its own documentation says so); use it for building and debugging only, then disable it.
How extraction fits in the plan
An extractor is a post-processor. After a sampler runs, JMeter runs the post-processors in its scope, in tree order,
before the assertions and the listeners (see
Test Plan Elements, Execution Order & Scoping).
The extractor reads the sampler’s result (body, headers, URL, code or message, depending on its settings) and writes
one or more JMeter variables. Variables belong to the thread, so each virtual user has its own token and its own
loanId. The next sampler then references them as ${token} or ${loanId}, and JMeter substitutes the
values just before that sampler runs.
Three consequences of that model shape everything below:
-
Place each extractor as a child of the sampler whose response holds the value. The component reference says that post-processors apply to every sampler in their scope. An extractor placed directly under the Thread Group runs after every sampler of the thread and overwrites the variable each time, usually with the default value. The JSON Extractor’s documentation states explicitly that it must be placed as a child of the sampler.
-
Extractors run before assertions. An extractor cannot see whether an assertion failed, and the sample status it sees is the sampler’s own. To act on a failed extraction, add an assertion on the variable or on the response, and a Result Status Action Handler (described below) to decide what the thread does next.
-
Extractors apply to the parent sample only, unless told otherwise. The default Apply to setting is Main sample only. Sub-samples (embedded resources, redirects, children of a Transaction Controller in parent mode) are only searched when Apply to says so.
Fields shared by most extractors
Two settings appear in almost every extractor and behave the same way in all of them.
Apply to. Chooses which sample results the extractor reads.
| Option | Meaning | JMX value (Sample.scope) |
|---|---|---|
Main sample only |
Only the sampler’s own result. The default; JMeter does not write the property for it. |
|
Sub-samples only |
Only the sub-samples: embedded resources, followed redirects, the children of a Transaction Controller that generates a parent sample, the messages of a Mail Reader. |
|
Main sample and sub-samples |
Both, main sample first. |
|
JMeter Variable Name to use |
The content of a JMeter variable instead of a response; the variable name goes in the text field next to the option. Useful to extract from a value an earlier extractor captured (a JSON fragment, a decoded header). |
|
When several samples qualify, the Regular Expression, CSS Selector and Boundary Extractors count matches across them in order. The component reference gives the example of a main sample and three sub-samples with one match each: with Match No. 3 and Sub-samples only the extractor uses the third sub-sample; with Main sample and sub-samples it uses the second sub-sample, because the first match is the main sample. With Match No. 0 or negative every qualifying sample is processed; with a positive number matching stops as soon as enough matches have been found.
Match No. (0 for Random). Chooses which match is stored when the expression matches several times.
| Value | Effect |
|---|---|
|
A random match. Useful to pick a random book from a search result per iteration; harmful when the value must be deterministic. |
|
The N-th match. If there are fewer than N matches, the default value is used. |
|
All matches, stored as numbered variables |
Always fill Match No. explicitly. The JSON Extractor documents that an empty field means 0 for every expression,
and the 5.6.3 JMESPath code reads an empty field as 0 too: a random pick, which is rarely what a correlation needs.
An empty field never means "the first match".
JSON Extractor
The JSON Extractor (class JSONPostProcessor) evaluates one or more JSONPath expressions against a JSON response and
stores the results in variables. It uses the Jayway JsonPath library. It is the natural choice for REST APIs like
Bookshelf: it is easy to read, it understands nesting and arrays, and one element can extract several values at once.
Add it with right-click the sampler → Add → Post Processors → JSON Extractor.
| Field (GUI label) | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
Apply to |
Main sample only, Sub-samples only, Main sample and sub-samples, or JMeter Variable Name to use (see above). |
Yes |
Names of created variables |
Semicolon-separated variable names, one per JSONPath expression. JMX: |
Yes |
JSON Path expressions |
Semicolon-separated JSONPath expressions; their number must match the number of variable names. JMX:
|
Yes |
Match No. (0 for Random) |
Semicolon-separated list, one number per expression: |
No |
Default Values |
Semicolon-separated defaults, one per expression, used when the expression returns no result. JMX:
|
No |
Compute concatenation var (suffix _ALL) |
When ticked and the match number is |
No |
The variable names, expressions and default values must have the same number of entries. If they do not, 5.6.3 logs "Number of JSON Path variables must match number of default values and json-path expressions" and the extractor fails for that sample. Two consequences follow:
-
With three expressions, write three defaults, even if they are the same:
NOT_FOUND;NOT_FOUND;NOT_FOUND. -
A trailing empty default does not work in 5.6.3.
NOT_FOUND;is split into one entry, not two, so the counts no longer match. Use an explicit placeholder in the last position. The planned 6.0 change log lists a fix that supports trailing empty default values.
JSONPath in five minutes
The component reference links to the Jayway JsonPath syntax. The parts used in load tests:
| Expression | Selects |
|---|---|
|
The |
|
A nested field. |
|
The |
|
The |
|
Every |
|
A filter: ids of books with copies available. |
|
A function: the size of the array. |
A JSONPath result that is an object or an array is stored as JSON text; a string, number or boolean is stored as its
text. A null value gives the default value (fixed in 5.5).
Variables set by the JSON Extractor
The component reference only documents name_N and name_ALL. The 5.6.3 source (JSONPostProcessor) is more
precise, and the differences matter when a ForEach Controller or an If Controller reads name_matchNr:
| Situation | Variables written |
|---|---|
Match No. |
|
Match No. |
|
Match No. |
|
Match No. |
|
Expression returns no result (any match number) |
|
Response body empty, or the source variable missing |
|
Before each run the extractor removes the previous name_matchNr and name_1, name_2… of the same thread, so
stale numbered values from the previous iteration do not leak into the next one.
Example: the token and the search results in one extractor each
The Bookshelf login returns {"token":"<jwt>","tokenType":"Bearer","expiresIn":900} and the search returns
{"items":[{"id":42,"title":"...","copiesAvailable":3},...],"total":17}.
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Extract token">
<stringProp name="JSONPostProcessor.referenceNames">token;tokenTtl</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.token;$.expiresIn</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1;1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">TOKEN_NOT_FOUND;0</stringProp>
</JSONPostProcessor>
<hashTree/>
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Extract book ids">
<stringProp name="JSONPostProcessor.referenceNames">bookId</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.items[*].id</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">-1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">NO_BOOK</stringProp>
<boolProp name="JSONPostProcessor.compute_concat">true</boolProp>
</JSONPostProcessor>
<hashTree/>
After a search with three hits the thread holds bookId_1=42, bookId_2=7, bookId_3=19, bookId_matchNr=3 and
bookId_ALL=42,7,19. After a search with no hit it holds bookId=NO_BOOK and bookId_matchNr=0, and no
bookId_1.
JSON JMESPath Extractor
The JSON JMESPath Extractor (class JMESPathExtractor, added in 5.2) does the same job with JMESPath, a JSON query
language with a complete ABNF grammar and specification, so expressions behave the same in every JMESPath
implementation (the AWS CLI uses it, for instance). It handles one expression per element, unlike the JSON
Extractor.
Add it with Add → Post Processors → JSON JMESPath Extractor.
| Field (GUI label) | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
Apply to |
Main sample only, Sub-samples only, Main sample and sub-samples, or JMeter Variable Name to use. |
Yes |
Names of created variables |
The variable name (one only; the label is shared with the JSON Extractor). JMX: |
Yes |
JMESPath expressions |
One JMESPath expression. JMX: |
Yes |
Match No. (0 for Random) |
|
No |
Default Values |
The value stored when nothing matches. JMX: |
No |
An expression that returns a JSON array is split into its elements, so items[*].id yields one result per book. Text
results are stored without quotes; numbers, objects and arrays are stored as JSON text.
Variables. In 5.6.3 (JMESPathExtractor), name_matchNr is written whenever the expression returns something,
whatever the match number (also for 0), and is 0 when it returns nothing. With -1, name_1 … name_N are
written and name is left untouched; with no result name gets the default. An empty response sets only the
default.
<JMESPathExtractor guiclass="JMESPathExtractorGui" testclass="JMESPathExtractor" testname="Pick an available book">
<stringProp name="JMESExtractor.referenceName">availableBookId</stringProp>
<stringProp name="JMESExtractor.jmesPathExpr">items[?copiesAvailable > `0`].id</stringProp>
<stringProp name="JMESExtractor.matchNumber">0</stringProp>
<stringProp name="JMESExtractor.defaultValue">NO_AVAILABLE_BOOK</stringProp>
</JMESPathExtractor>
<hashTree/>
This picks a random book that can be borrowed. In JMESPath literals are written between backticks, so the number
zero is `0`. The JSONPath equivalent is $.items[?(@.copiesAvailable > 0)].id.
JSON Extractor or JMESPath? Both are core, both parse the whole body. Choose the JSON Extractor when one element
should extract several values, or when the team already knows JSONPath; choose JMESPath for its precise
specification, projections and functions (length, sort_by, max_by…). Do not use both on the same response
for the same value.
Regular Expression Extractor
The Regular Expression Extractor (class RegexExtractor) applies a Perl-style regular expression to a chosen part of
the result and builds the stored value from a template that refers to the capture groups. It works on any text: JSON
when a JSONPath parser is overkill, HTML, headers, the URL, the response code. It is the oldest extractor and the one
the books use for everything.
Add it with Add → Post Processors → Regular Expression Extractor.
| Field (GUI label) | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
Apply to |
Main sample only, Sub-samples only, Main sample and sub-samples, or JMeter Variable Name to use. |
Yes |
Field to check |
Which part of the result is searched: Body, Body (unescaped), Body as a Document, Request Headers,
Response Headers, URL, Response Code or Response Message (table below). JMX: |
Yes |
Name of created variable |
The variable name, |
Yes |
Regular Expression |
The expression. It must contain at least one capture group |
Yes |
Template ($i$ where i is capturing group number, starts at 1) |
How the value is built from the match: |
Yes |
Match No. (0 for Random) |
|
Yes |
Default Value |
Stored in |
No |
Use empty default value |
When ticked and Default Value is empty, |
No |
| Field to check | Searches | JMX value |
|---|---|---|
Body |
The response body, without headers. The default. |
|
Body (unescaped) |
The body with every HTML escape code replaced, without regard to context. The manual warns that this option "highly impacts performances". |
|
Body as a Document |
Text extracted by Apache Tika from a document response (PDF, Office files, see the Apache Tika section). Also costly. |
|
Request Headers |
The headers JMeter sent. May be absent for non-HTTP samplers. |
|
Response Headers |
The headers received, one per line. May be absent for non-HTTP samplers. |
|
URL |
The sampled URL (after redirects, the final one). |
|
Response Code |
For example |
|
Response Message |
For example |
|
The JMX name useHeaders is historical: false means "use the body", true means "response headers", and the other
options have their own values.
Variables set by the Regular Expression Extractor
This is the extractor whose variables the component reference documents in full, and the reference for the -1
rule.
Match No. 0 or N > 0, and a match is found:
-
refName= the template applied to the match; -
refName_g0,refName_g1, … = the whole match and each group; -
refName_g= the number of groups in the expression (excluding group 0).
Match No. 0 or N > 0, no match: refName = the default (only if a default is given or Use empty default value
is ticked), and refName_g0, refName_g1, … and refName_g are removed.
Match No. negative (all matches):
-
refName_matchNr= the number of matches, which can be0; -
refName_1,refName_2, … = the template applied to each match; -
refName_1_g0,refName_1_g1, … = the groups of each match; -
refName= always the default value, andrefName_g0,refName_g1… are not set.
refName_matchNr is written only in the negative mode; in the other modes it is removed. Numbered variables left
over from a previous run with more matches are removed too.
Worked example. The search response contains three books and the extractor uses the regular expression
"id":(\d+),"title":"([^"]+)", the template $1$, Match No. -1, the name book and the default
NO_BOOK:
| Variable | Value |
|---|---|
|
|
|
|
|
|
|
|
|
|
With Match No. 1 instead, the variables are book=42, book_g0="id":42,"title":"Dune", book_g1=42,
book_g2=Dune and book_g=2, and no book_matchNr.
Example: the new loan id from the Location header
POST /api/loans answers 201 Created with a Location: /api/loans/1001 header. A header is plain text, so a
regular expression on Response Headers is the right tool:
<RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Loan id from Location">
<stringProp name="RegexExtractor.useHeaders">true</stringProp>
<stringProp name="RegexExtractor.refname">loanIdFromHeader</stringProp>
<stringProp name="RegexExtractor.regex">(?im)^location:\s*\S*/api/loans/(\d+)</stringProp>
<stringProp name="RegexExtractor.template">$1$</stringProp>
<stringProp name="RegexExtractor.default">LOANID_NOT_FOUND</stringProp>
<stringProp name="RegexExtractor.match_number">1</stringProp>
<boolProp name="RegexExtractor.default_empty_value">false</boolProp>
</RegexExtractor>
<hashTree/>
(?i) makes the match case-insensitive, because HTTP header names are case-insensitive (an HTTP/2 server sends
location). (?m) (multi-line mode, below) makes ^ match at the start of every header line: the user manual’s
regular expressions chapter describes ^ as matching only at the start of the whole text by default, and the
response headers start with the status line, so the flag is stated explicitly. \S* accepts both a relative path
and an absolute URL.
Regular expression syntax in JMeter
The rules come from the Regular Expressions chapter of the user manual.
Engine. By default JMeter uses Apache Jakarta ORO, a Perl 5 compatible engine. Since 5.5 the JMeter property
jmeter.regex.engine switches to the JDK’s java.util.regex when set to any value other than oro. The property is
read once at start-up, so set it in user.properties or with -J, never in the plan.
# user.properties: use the JDK regex engine instead of ORO (5.5 and later)
jmeter.regex.engine=java
Source: Regular Expressions: Overview
No delimiters, embedded modifiers. Do not write /abc/i. Write (?i)abc. Modifiers can be placed anywhere and
apply from that point on, so Match ExAct case or (?i)ArBiTrARY(?-i) case ignores case only in the middle part. An
ORO bug prevents modifiers at the very end of an expression, where they would have no effect anyway.
Line modes. Single-line mode (?s) lets . match a newline as well. Multi-line mode (?m) makes ^ and $ match
at the start and end of every line instead of only at the start and end of the whole text. The two are independent.
Response headers and HTML bodies are multi-line, so these modes matter.
Meta-characters to escape with a backslash: ( ), [ ], { }, * + ?, ., \, |, ^ and $.
ORO does not support \Q...\E quoting; the __escapeOroRegexpChars function escapes a value instead, for example
${__escapeOroRegexpChars(valueToEscape)}.
Supported Perl 5 extensions in ORO: (?#text) comments, (?:regexp) non-capturing groups, (?=regexp) positive
look-ahead, (?!regexp) negative look-ahead, and the (?imsx) modifiers. Look-behind (?<=regexp) is not
supported by ORO (it is by the Java engine).
Lazy and negated classes. The manual’s example extracts readme.txt from name="file" value="readme.txt"> with
name="file" value="(.+?)">, where +? stops at the first possible end. It then recommends the more
efficient name="file" value="([^"]+)">: a negated class [^"] lets the engine stop at the first
quote instead of checking every possible end. The same pattern gives the Bookshelf token:
"token"\s*:\s*"([^"]+)".
"Contains" versus "matches". In the Response Assertion, "contains" means the expression matches part of the text, "matches" means it matches the whole text. Extractors search, so they behave like "contains".
Testing. Use the View Results Tree Regexp Tester on a real response, or a small plan with a Debug Sampler: the manual suggests generating a sample with a Java Request or an HTTP Request that loads a file, so expressions can be tested without a server.
Source: Regular Expressions
Boundary Extractor
The Boundary Extractor (class BoundaryExtractor, added in 4.0) extracts the text between a left boundary and a
right boundary, with no regular expression at all. The 4.0 release notes present it as "easy extraction with better
performances". It is the cheapest extractor for a value that always sits between the same two literal strings.
Add it with Add → Post Processors → Boundary Extractor.
| Field (GUI label) | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
Apply to |
Main sample only, Sub-samples only, Main sample and sub-samples, or JMeter Variable Name to use. Counting across several samples works as for the Regular Expression Extractor. |
Yes |
Field to check |
Same options as the Regular Expression Extractor: Body, Body (unescaped), Body as a Document, Request Headers,
Response Headers, URL, Response Code, Response Message. JMX: |
Yes |
Name of created variable |
The variable name. JMX: |
Yes |
Left Boundary |
Literal text immediately before the value. JMX: |
No |
Right Boundary |
Literal text immediately after the value. JMX: |
No |
Match No. (0 for Random) |
|
Yes |
Default Value |
Stored when the boundaries do not match. "No, but recommended". JMX: |
No |
Use empty default value |
Present in the 5.6.3 GUI although the component reference table does not list it: as in the Regular Expression
Extractor, sets an empty string instead of leaving the variable unset. JMX: |
No |
Both boundaries may be empty (since 5.2); if both are empty, the whole selected data is returned.
Variables. With a non-negative match number, name = the extracted text, or the default when nothing matches
(only if a default is set or the empty-default box is ticked). With a negative match number, name_matchNr = the
number of matches (possibly 0) and name_1, name_2… the values, while name holds the default. The component
reference also lists name_n_gm group variables for this mode, copied from the regex documentation; a boundary
extraction has no groups, and the 5.6.3 code (BoundaryExtractor) does not write them. name_matchNr exists only in
the negative mode.
<BoundaryExtractor guiclass="BoundaryExtractorGui" testclass="BoundaryExtractor" testname="Token (boundary)">
<stringProp name="BoundaryExtractor.useHeaders">false</stringProp>
<stringProp name="BoundaryExtractor.refname">token</stringProp>
<stringProp name="BoundaryExtractor.lboundary">"token":"</stringProp>
<stringProp name="BoundaryExtractor.rboundary">"</stringProp>
<stringProp name="BoundaryExtractor.match_number">1</stringProp>
<stringProp name="BoundaryExtractor.default">TOKEN_NOT_FOUND</stringProp>
<boolProp name="BoundaryExtractor.default_empty_value">false</boolProp>
</BoundaryExtractor>
<hashTree/>
The price of speed is fragility: the boundaries are literal, so "token": " (with a space) or a different field
order breaks the extraction silently, apart from the default value. Use it when the format is under the team’s
control, and the JSON Extractor when it is not.
CSS Selector Extractor
The CSS Selector Extractor (class HtmlExtractor; called CSS/JQuery Extractor until 5.0) selects nodes of an HTML
response with a CSS selector and stores an attribute value or the node’s text. It is the right extractor for HTML: the
component reference says that for HTML the CSS Selector Extractor is "the correct and performing solution", and that
XPath should not be used for HTML.
Add it with Add → Post Processors → CSS Selector Extractor.
| Field (GUI label) | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
Apply to |
Main sample only, Sub-samples only, Main sample and sub-samples, or JMeter Variable Name to use. |
Yes |
CSS Selector Extractor Implementation |
JSoup or Jodd-Lagarto (CSSelly). Empty means the default, JSoup. The two syntaxes differ slightly. JMX:
|
No |
Name of created variable |
The variable name. JMX: |
Yes |
CSS Selector expression |
The selector. Selectors, combinations and pseudo-selectors are supported, for example |
Yes |
Attribute |
The attribute to read from the matched node (JSoup |
No |
Match No. (0 for Random) |
|
Yes |
Default Value |
Stored when nothing matches. "No, but recommended". JMX: |
No |
Use empty default value |
Sets an empty string instead of leaving the variable unset (since 3.1). JMX: |
No |
Variables. With a non-negative match number, name = the value, or the default. With a negative match number,
name_matchNr = the number of matches (possibly 0), name_1, name_2… the values, and name = the default.
There are no group variables, and name_matchNr exists only in the negative mode.
Bookshelf is a JSON API, so the example uses a hypothetical server-rendered admin form with a CSRF token,
<input type="hidden" name="_csrf" value="...">:
<HtmlExtractor guiclass="HtmlExtractorGui" testclass="HtmlExtractor" testname="CSRF token">
<stringProp name="HtmlExtractor.refname">csrf</stringProp>
<stringProp name="HtmlExtractor.expr">input[name=_csrf]</stringProp>
<stringProp name="HtmlExtractor.attribute">value</stringProp>
<stringProp name="HtmlExtractor.default">CSRF_NOT_FOUND</stringProp>
<stringProp name="HtmlExtractor.match_number">1</stringProp>
<stringProp name="HtmlExtractor.extractor_impl"></stringProp>
<boolProp name="HtmlExtractor.default_empty_value">false</boolProp>
</HtmlExtractor>
<hashTree/>
The form POST then sends _csrf with the value ${csrf}. When the server sets the token in a cookie instead, no
extractor is needed if the property CookieManager.save.cookies is true: the Cookie Manager then also stores each
cookie as a variable named COOKIE_ followed by the cookie name; see
HTTP Sessions, Headers, Cookies & Authentication.
XPath2 Extractor
The XPath2 Extractor (class XPath2Extractor, added in 5.0) evaluates an XPath 2.0 query against an XML or XHTML
response. It is backed by Saxon. Since 5.0 the component reference recommends it over the older XPath Extractor for
"better and easier namespace management, better performances and support for XPath 2.0". Use it for XML APIs and SOAP
responses; for HTML use the CSS Selector Extractor.
Add it with Add → Post Processors → XPath2 Extractor.
| Field (GUI label) | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
Apply to |
Main sample only, Sub-samples only, Main sample and sub-samples, or JMeter Variable Name to use. All matching results of all qualifying samples are returned. |
Yes |
Return entire XPath fragment instead of text content? |
When ticked, the matched node is returned as XML ( |
Yes |
Name of created variable |
The variable name. JMX: |
Yes |
XPath query |
An XPath 2.0 expression; it may return several nodes. XPath 2.0 functions such as |
Yes |
Match No. (0 for Random) |
|
No |
Default Value |
Returned when nothing matches, and when the node has no value and the fragment option is off. JMX:
|
Yes |
Namespaces aliases list |
One |
No |
Variables. The component reference says the XPath2 Extractor works "exactly the same" as the XPath Extractor for
ForEach use, and the 5.6.3 code confirms it: whatever the match number, the extractor first sets name to the
default and name_matchNr to 0, then writes name_matchNr = the number of values kept, name = the first value
kept, and name_1 … name_N. With Match No. -1 that is every result; with N or 0 it is the one selected
value, so name_matchNr is 1 and name_1 equals name. This makes XPath2 the only extractor here that sets both
name and name_matchNr in every mode.
A hypothetical XML representation of the Bookshelf search, in namespace urn:bookshelf:v1:
<XPath2Extractor guiclass="XPath2ExtractorGui" testclass="XPath2Extractor" testname="Book ids (XML)">
<stringProp name="XPathExtractor2.default">NO_BOOK</stringProp>
<stringProp name="XPathExtractor2.refname">bookIdXml</stringProp>
<stringProp name="XPathExtractor2.matchNumber">-1</stringProp>
<stringProp name="XPathExtractor2.xpathQuery">/bs:books/bs:book/bs:id</stringProp>
<boolProp name="XPathExtractor2.fragment">false</boolProp>
<stringProp name="XPathExtractor2.namespaces">bs=urn:bookshelf:v1</stringProp>
</XPath2Extractor>
<hashTree/>
The older XPath Extractor (class XPathExtractor) still exists, with Tidy options for HTML (Use Tidy, Quiet, Report
Errors, Show warnings) and XML parser options (Use Namespaces, Validate XML, Ignore Whitespace, Fetch External DTDs),
and namespaces declared through the xpath.namespace.config property. New plans should not use it.
Which extractor sets what: the -1 and _matchNr rules
The extractors look alike in the GUI but do not write the same variables. This table summarises the sections above
for the 5.6.3 code; name is the variable name configured in the element.
| Extractor | name_matchNr written when |
name with Match No. -1 |
Other variables |
|---|---|---|---|
Regular Expression |
Only with a negative Match No. ( |
Always the default value. |
|
Boundary |
Only with a negative Match No. |
The default value, if one is set. |
|
CSS Selector |
Only with a negative Match No. |
The default value, if one is set. |
|
XPath2 |
Always: the number of values kept ( |
The first match (default if none). |
|
JSON Extractor |
With |
Not written: keeps its previous value (default if no result). |
|
JSON JMESPath |
Whenever there are results (any Match No.); |
Not written: keeps its previous value (default if no result). |
|
Two practical rules follow:
-
To loop over all matches, use
-1and readname_matchNrfor the count. Every extractor supports this, and the ForEach Controller only needs the numbered variables. -
Do not read
nameafter a-1extraction. Depending on the extractor it is the default, the first match, or a stale value from an earlier sample. Readname_1instead.
Source: Post-Processors (Component Reference) and the 5.6.3 sources in org.apache.jmeter.extractor
Result Status Action Handler
The Result Status Action Handler (class ResultAction) does not extract anything. It decides what the thread does
when the sampler in its scope fails, "either because the sample itself failed or an assertion failed". It is the
per-sampler version of the Thread Group’s "Action to be taken after a Sampler error", and it belongs on this page
because a failed correlation is the most common reason to stop a user: without a token, every later request of the
journey only adds 401 errors to the results.
Add it with Add → Post Processors → Result Status Action Handler.
| Field (GUI label) | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
Action to be taken after a Sampler error |
What happens when the sample is marked failed. JMX: |
No |
| Option | Effect | OnError.action |
|---|---|---|
Continue |
Ignore the error and continue. The default. |
|
Start Next Thread Loop |
Skip the rest of the current Thread Group iteration and start the next one. |
|
Go to the next iteration of Current Loop |
Skip the rest of the innermost loop (Loop, While, ForEach Controller) and start its next iteration. |
|
Break Current Loop |
Leave the innermost loop. |
|
Stop Thread |
The current thread exits. |
|
Stop Test |
The whole test stops at the end of the current samples. |
|
Stop Test Now |
The whole test stops abruptly; current samplers are interrupted if possible. |
|
The component reference table lists five choices; the two current-loop options were added in 5.0 ("Loop breaking and Loop switching to next iteration") and appear in the 5.6.3 GUI. The handler runs after the assertions of the sample (it reacts to the final status), so an assertion that checks the extracted value can trigger it.
<ResultAction guiclass="ResultActionGui" testclass="ResultAction" testname="Restart iteration if login failed">
<intProp name="OnError.action">4</intProp>
</ResultAction>
<hashTree/>
Which action under load? Stop Thread lowers the concurrency for the rest of the run, so the test silently stops applying the planned load; Stop Test ends the run on the first failure, which suits a smoke test but not a load test. Start Next Thread Loop keeps the user alive and tries again on the next iteration, which keeps the concurrency constant and is usually the right choice. Whatever the action, failed logins still appear as errors in the results.
Supporting techniques
Default values that make failures visible
Every extractor has a default value, and the component reference recommends setting one: without it, there is no way
to tell whether the expression did not match, the extractor did not run, or a different variable name was used. Use a
loud, unmistakable default such as TOKEN_NOT_FOUND or LOANID_NOT_FOUND, never a plausible value like 0 or
1.
A visible default turns a silent correlation failure into an obvious one:
-
the next request carries
Bearer TOKEN_NOT_FOUNDor/api/loans/LOANID_NOT_FOUND, which is easy to spot in the View Results Tree and in the server logs; -
an assertion can check for it. A Response Assertion on the JMeter Variable
tokenwith the patternTOKEN_NOT_FOUNDand Not ticked fails the login sample when extraction failed, and the Result Status Action Handler above then acts on it (see Assertions); -
an If Controller can skip dependent requests:
${__groovy(vars.get("loanId") != "LOANID_NOT_FOUND")}.
When several extractors deliberately write the same variable (one of several possible responses), the component reference suggests removing the default once debugging is finished, so a non-matching extractor leaves the value from the matching one in place. Use empty default value is for genuinely optional values, where an empty string is a valid answer.
ForEach over all matches
With Match No. -1 every extractor writes name_1 … name_N, the input the ForEach Controller expects. The
controller and its fields are described in
Logic Controllers & Transactions; the
Bookshelf plan opens the first three search results:
<ForeachController guiclass="ForeachControlPanel" testclass="ForeachController" testname="Open first results">
<stringProp name="ForeachController.inputVal">bookId</stringProp>
<stringProp name="ForeachController.returnVal">currentBookId</stringProp>
<boolProp name="ForeachController.useSeparator">true</boolProp>
<stringProp name="ForeachController.startIndex">0</stringProp>
<stringProp name="ForeachController.endIndex">3</stringProp>
</ForeachController>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="GET /api/books/{id}">
<stringProp name="HTTPSampler.path">/api/books/${currentBookId}</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
Two alternatives avoid the loop when only one value is needed:
-
Match No.
0stores a random match directly inname. -
With
-1, a function picks an index:${__V(bookId_${__Random(1,${bookId_matchNr})})}.__Randomreturns a number between 1 and the match count (both inclusive) and__Vevaluates the composed variable name. Guard it with an If Controller on${bookId_matchNr}greater than 0, because__Random(1,0)is not a valid range.
To loop over the groups of one regex match (name_g1, name_g2…), untick Use Separator in the ForEach
Controller and use name_g as the prefix.
Source: ForEach Controller (Component Reference) and Functions
Debug Sampler and Debug PostProcessor
Two elements show the variables an extractor produced, in the View Results Tree’s Response data pane.
Debug Sampler (Add → Sampler → Debug Sampler) generates a sample containing the current values of the JMeter variables and/or properties. Place it right after the sampler being debugged.
| Field | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
JMeter Properties |
Include JMeter properties. |
Yes |
JMeter Variables |
Include JMeter variables. |
Yes |
System Properties |
Include Java system properties. |
Yes |
Debug PostProcessor (Add → Post Processors → Debug PostProcessor) adds a sub-sample to the previous sampler’s result with the sampler’s properties, the variables, the JMeter properties and/or the system properties. Being a post-processor, it runs after the extractors placed above it under the same sampler, so it shows their output for that exact sample.
| Field | Meaning | Required |
|---|---|---|
Name |
Descriptive name shown in the tree. |
No |
JMeter Properties |
Show JMeter properties (default false). |
Yes |
JMeter Variables |
Show JMeter variables (default false). |
Yes |
Sampler Properties |
Show the sampler’s properties (default true). |
Yes |
System Properties |
Show Java system properties (default false). |
Yes |
<DebugPostProcessor guiclass="TestBeanGUI" testclass="DebugPostProcessor" testname="Debug PostProcessor">
<boolProp name="displayJMeterProperties">false</boolProp>
<boolProp name="displayJMeterVariables">true</boolProp>
<boolProp name="displaySamplerProperties">false</boolProp>
<boolProp name="displaySystemProperties">false</boolProp>
</DebugPostProcessor>
<hashTree/>
With JMeter Variables ticked, the sub-sample’s response data lists the thread’s variables in alphabetical order, for example (shortened, values illustrative):
JMeterVariables:
JMeterThread.last_sample_ok=true
loanId=1001
loanIdFromHeader=1001
loanStatus=PENDING
token=eyJhbGciOiJIUzI1NiJ9.<shortened>
tokenTtl=900
Both elements are debugging aids. Disable them before a load run: the Debug Sampler adds samples to the results and both copy every variable into a result for every iteration, which costs memory and CPU and pollutes the statistics.
Worked example: the Bookshelf login token and the new loan id
The Bookshelf journey logs in, searches, views a book, creates a loan and views it. Two values must be correlated:
-
the JWT from
POST /api/auth/login, sent asAuthorization: Bearer <token>on every later request; -
the loan id from
POST /api/loans, used in the path ofGET /api/loans/{id}.
The exchanges, with the values the extractors capture, are:
POST /api/auth/login
Content-Type: application/json
{"username":"reader001","password":"<from users.csv>"}
HTTP/1.1 200 OK
Content-Type: application/json
{"token":"eyJhbGciOiJIUzI1NiJ9.<shortened>","tokenType":"Bearer","expiresIn":900}
POST /api/loans
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.<shortened>
Content-Type: application/json
{"bookId":42}
HTTP/1.1 201 Created
Location: /api/loans/1001
Content-Type: application/json
{"id":1001,"bookId":42,"status":"PENDING"}
Step by step in the GUI
-
Under the login sampler
POST /api/auth/login, add Add → Post Processors → JSON Extractor. Set Names of created variables totoken, JSON Path expressions to$.token, Match No. to1and Default Values toTOKEN_NOT_FOUND. -
Under the same sampler, add Add → Assertions → JSON Assertion with Assert JSON Path exists set to
$.token, so a login without a token is a failed sample (see Assertions). -
Under the same sampler, add Add → Post Processors → Result Status Action Handler and select Start Next Thread Loop.
-
Add a Simple Controller named "Authenticated requests" (Add → Logic Controller → Simple Controller) after the login, move the search, view and loan requests into it, and add to it Add → Config Element → HTTP Header Manager with the header
Authorizationand the valueBearer ${token}. The Header Manager is resolved when each sampler runs, so every request in the controller sends the token captured at login, and the login request itself sends noAuthorizationheader (scoping is explained in Test Plan Elements, Execution Order & Scoping). -
Under
POST /api/loans, add a JSON Extractor with Names of created variablesloanId;loanStatus, JSON Path expressions$.id;$.status, Match No.1;1and Default ValuesLOANID_NOT_FOUND;UNKNOWN. -
Optionally, under the same sampler, add the Regular Expression Extractor on Response Headers shown earlier, to cross-check the id in the
Locationheader while debugging. -
In
GET /api/loans/{id}, set Path to/api/loans/${loanId}. -
Add a Debug PostProcessor under
POST /api/loansand a View Results Tree, run the plan with one thread (Validate on the Thread Group), and check thattoken,loanIdandloanStatushold real values. -
Disable the Debug PostProcessor and the View Results Tree before any load run.
The resulting test plan fragment
<OnceOnlyController guiclass="OnceOnlyControllerGui" testclass="OnceOnlyController" testname="Login once per user"/>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="POST /api/auth/login">
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">{"username":"${username}","password":"${password}"}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.path">/api/auth/login</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
</HTTPSamplerProxy>
<hashTree>
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Extract token">
<stringProp name="JSONPostProcessor.referenceNames">token</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.token</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">TOKEN_NOT_FOUND</stringProp>
</JSONPostProcessor>
<hashTree/>
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="Token present">
<stringProp name="JSON_PATH">$.token</stringProp>
<stringProp name="EXPECTED_VALUE"></stringProp>
<boolProp name="JSONVALIDATION">false</boolProp>
<boolProp name="EXPECT_NULL">false</boolProp>
<boolProp name="INVERT">false</boolProp>
<boolProp name="ISREGEX">false</boolProp>
</JSONPathAssertion>
<hashTree/>
<ResultAction guiclass="ResultActionGui" testclass="ResultAction" testname="Retry next iteration if login failed">
<intProp name="OnError.action">4</intProp>
</ResultAction>
<hashTree/>
</hashTree>
</hashTree>
<GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Authenticated requests"/>
<hashTree>
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="Bearer token">
<collectionProp name="HeaderManager.headers">
<elementProp name="" elementType="Header">
<stringProp name="Header.name">Authorization</stringProp>
<stringProp name="Header.value">Bearer ${token}</stringProp>
</elementProp>
</collectionProp>
</HeaderManager>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="POST /api/loans">
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">{"bookId":${bookId}}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.path">/api/loans</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
</HTTPSamplerProxy>
<hashTree>
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Extract loan id">
<stringProp name="JSONPostProcessor.referenceNames">loanId;loanStatus</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.id;$.status</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1;1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">LOANID_NOT_FOUND;UNKNOWN</stringProp>
</JSONPostProcessor>
<hashTree/>
</hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="GET /api/loans/{id}">
<stringProp name="HTTPSampler.path">/api/loans/${loanId}</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
The fragment shows only the properties that matter. The Content-Type header (application/json) of the two POST
requests, the search and view requests that set bookId, the HTTP Request Defaults with ${__P(host,localhost)} and
${__P(port,8080)}, the CSV Data Set Config for users.csv, timers and Transaction Controllers come from the other
pages of this guide. Build the plan in the GUI and read the XML to review it rather than writing whole plans by hand.
Checking the correlation from the command line
A one-user smoke run in CLI mode confirms the correlation before any load is applied. With the canonical run properties of this guide:
jmeter -n -t bookshelf-load.jmx -Jthreads=1 -Jrampup=1 -Jduration=30 -Jhost=localhost -Jport=8080 -l smoke.jtl
The summariser prints lines of this form (numbers illustrative):
summary = 25 in 00:00:30 = 0.8/s Avg: 38 Min: 6 Max: 142 Err: 0 (0.00%)
Err: 0 means no sample failed, so every request ran with a real token and a real loan id. A failed correlation
shows up immediately as errors on the requests after the extraction (401 without a token, 404 for
/api/loans/LOANID_NOT_FOUND). To find the extraction that failed, search the results for the default values:
grep -c "LOANID_NOT_FOUND\|TOKEN_NOT_FOUND" smoke.jtl
This only finds them if the URL is saved in the JTL (jmeter.save.saveservice.url=true, off by default) or if the
default appears in a sample label or failure message; otherwise rerun the single user with the View Results Tree.
Worked numbers: how often the extractors run
Extractors run per sample, per thread, so their cost scales with the request rate, not with the number of extractors in the tree. With the load profile of this guide (50 threads, 60 s ramp-up, 660 s scheduler duration) and the Bookshelf mix (60 % search only, 30 % browse and borrow, 10 % login-heavy), take the mean iteration of about 8.5 s (Z = 3 s of think time per request included) worked out in Logic Controllers & Transactions, so at full load the 50 threads complete 50 / 8.5 ≈ 5.9 iterations per second:
-
Token extraction, login once per user: 50 executions in the whole run, one per thread, plus the logins of the login-heavy iterations: 10 % × 5.9 ≈ 0.6 per second.
-
Loan id extraction: only the browse-and-borrow iterations create loans: 30 % × 5.9 ≈ 1.8 per second.
-
A misplaced extractor: if the token JSON Extractor sat at Thread Group level instead of under the login sampler, it would run after every sample. At, say, 5 samples per iteration that is about 30 executions per second, 50 times more than needed, and each of them would overwrite
tokenwithTOKEN_NOT_FOUND, because the other responses have notokenfield. The second problem is the serious one: the test breaks, not only slows down.
Load-generator cost
Extractors run inside the load generator, in the thread that sends the requests, so a slow extractor delays the next request of that virtual user and lowers the achievable throughput. The official guidance and the implementations give this ranking, from cheapest to most expensive:
| Extractor | Cost driver |
|---|---|
Boundary Extractor |
Plain string search. Introduced in 4.0 for "better performances". |
Regular Expression Extractor |
Regex matching over the selected field. Cheap for anchored expressions and negated classes; expensive for
|
JSON Extractor and JSON JMESPath Extractor |
Parse the whole body into a tree. In the 5.6.3 JSON Extractor each expression is evaluated against the response text separately, so one element with five expressions parses five times. Cost grows with the body size. |
CSS Selector Extractor |
Parses the whole HTML document into a DOM. |
XPath2 Extractor |
Builds a full XML document with Saxon for every sample; the most expensive on large documents. The older XPath Extractor with Tidy is worse still. |
Field to check: Body (unescaped), Body as a Document |
The manual warns that unescaping "highly impacts performances" and that Body as a Document (Tika) can too. |
The rules that keep the cost down:
-
Scope every extractor to the one sampler that needs it.
-
Extract from the smallest field that contains the value: a header rather than the body when the value is in both.
-
Prefer one JSON Extractor with the expressions it needs to several elements, but remember that each expression is evaluated separately.
-
Avoid deep scans (
$..id) and greedy regular expressions on large responses. -
Remove Debug Sampler, Debug PostProcessor and View Results Tree before load runs.
Pitfalls
-
Extractor in the wrong scope. An extractor at Thread Group or controller level runs after every sampler and overwrites the variable, usually with the default. Put it under the sampler.
-
No default value. An unset variable stays as the literal text
${token}in the next request, which is hard to tell apart from a typo in the variable name. Always set a loud default while building the plan. -
Empty Match No. In the JSON and JMESPath Extractors it means
0, a random pick. With one match the result is the same, so the bug only shows when the response unexpectedly contains several matches. -
Reading
nameafter-1. See Which extractor sets what: the-1and_matchNrrules; readname_1andname_matchNr. -
Assuming
name_matchNrexists. It is not written by the Regular Expression, Boundary and CSS Selector Extractors unless Match No. is negative, and not by the JSON Extractor with Match No.0and results. An If Controller on${name_matchNr}then compares a literal string. -
JSON Extractor list lengths. Names, expressions and defaults must have the same count, and a trailing empty default does not count in 5.6.3.
-
Regular expressions over JSON or HTML. They break when the server changes whitespace, field order or escaping. Prefer the JSON, JMESPath or CSS Selector Extractor for structured content.
-
Header name case. HTTP/2 and many proxies send lower-case header names; use
(?i)in header regexes. -
Variables are per thread. A token extracted in a setUp Thread Group is not visible in the main Thread Group. Publish it as a property with
__setPropertyand read it with__P(see Properties, Variables & Functions). -
Token expiry in long tests. A JWT obtained once per user can expire during a soak test. Log in again on a schedule (with the
tokenTtlvalue extracted above) or make the server’s token lifetime longer than the test. -
Post-processors and sub-samples. Unless Apply to says otherwise, extractors only see the main sample. Before 5.5 the JSON and JMESPath extractors ignored sub-samples even when asked to read them (fixed in 5.5).
-
Correlation hidden behind redirects. With Follow Redirects, the final response is the main sample and the intermediate responses are sub-samples; a value in an intermediate
Locationheader needs Sub-samples only or Main sample and sub-samples.
From the books to 5.6 to 6.0
| Topic | In the books (JMeter 2.11 to 3.0) | 5.6.3 and planned 6.0 |
|---|---|---|
JSON extraction |
The |
Core JSON Extractor since 3.0 (renamed from "JSON Path PostProcessor" in 3.1), JSON JMESPath Extractor since 5.2. The
|
Scripted extraction |
BSF and BeanShell post-processors (PTwJ ch. 3; Pro ch. 3). |
BSF was deprecated in 3.1 (it still ships hidden in 5.6.3); use the JSR223 PostProcessor with Groovy and script caching (see Scripting with JSR223 & Groovy). 6.0 (planned) moves to Groovy 5. |
Boundary extraction |
Not available; regular expressions only. |
Boundary Extractor since 4.0, with empty boundaries allowed since 5.2. |
CSS selectors |
CSS/JQuery Extractor. |
Renamed CSS Selector Extractor in 5.0. 6.0 (planned) updates jsoup to 1.23.2. |
XPath |
XPath Extractor (XPath 1.0, Xalan, Tidy). |
XPath2 Extractor since 5.0 (Saxon). 6.0 (planned) updates Saxon-HE to 13.x. |
Regular expression engine |
ORO only. |
ORO by default; |
Body as a Document |
Tika 1.x. |
6.0 (planned) updates Apache Tika to 4.x. |
Result Status Action Handler |
Continue, Start next thread loop, Stop Thread, Stop Test, Stop Test Now. |
Plus Go to the next iteration of Current Loop and Break Current Loop since 5.0. |
References
-
Apache JMeter source (
xdocs/changes.xmlfor planned 6.0 changes; extractor sources undersrc/components/src/main/java/org/apache/jmeter/extractorat tagrel/v5.6.3for the variables each extractor sets) -
Bayo Erinle, JMeter Cookbook, Packt, 2014 (JMeter 2.11), chapter 2, and Performance Testing with JMeter, 2nd ed., Packt, 2015 (JMeter 2.12), chapters 3 and 7: correlation with the JSON Path Extractor plugin and scripted post-processors, used for concepts only.
-
Sai Matam and Jagdeep Jain, Pro Apache JMeter, Apress, 2017 (JMeter 3.0), chapter 3: BeanShell pre- and post-processors, used for concepts only.