JSON Extractor in JMeter: The Complete Advanced Guide

JSON Extractor in JMeter: The Complete Advanced Guide

Learn how the JSON Extractor captures values from API responses, how paths and match numbers choose the right data, which variables it creates, how defaults protect your test, and how to chain, loop and secure extracted values like an experienced performance engineer.

Think of a cloakroom at a theatre. You hand over your coat and receive a numbered ticket. Later, you cannot get your coat back unless you present that exact ticket. The number is different for every guest and every evening, so nobody can print the tickets in advance. Modern web services work in the same way. They hand out tickets, such as session tokens, order numbers and cart identifiers, that are different for every user and every call. A test that wants to continue its journey must catch the ticket from one reply and show it in the next request.

The JSON Extractor in JMeter is the element that catches the ticket. It reads a value from a JSON response, stores it in a variable that belongs to that virtual user, and makes it available to every later step. Without it, any API test that involves logging in, creating something or following a link breaks after the first step. This guide explains the JSON Extractor from the first idea to the advanced details: paths, match numbers, generated variables, default values, loops, token handling, performance cost, security and design patterns.

1What Is the JSON Extractor?

The element that catches a value from one reply so the next request can use it.

The simple definition

A post-processor in JMeter is an element that runs right after a request and works with its response. The JSON Extractor is a post-processor made for responses written in JSON, the data format used by most modern web services. You give it a JSON path, which is a short address that points to one place inside the response, and a variable name. After each request, the extractor follows the path, takes the value it finds, and stores it in the variable.

From then on, any element in the test plan can use that variable by writing its name inside the variable placeholder syntax. A header can carry the token, a request body can carry the identifier, an address can include the item number, and an assertion can compare against it. This simple mechanism is the foundation of realistic API tests.

Simple Analogy

The extractor is like a person at a hotel desk who reads your room number from the key card and writes it on a note for the porter. The room number is different for every guest, but the note makes sure every later step, such as sending luggage up, uses the right number.

The family history

Before JMeter included this element, teams installed a plugin to get the same function, and many older plans still mention it. Current versions include the JSON Extractor in the standard installation. It uses a widely known JSON path library, so the path syntax you learn here works in many other tools as well.

i
Practical Tip

Whenever a later request needs something that the server decided in an earlier reply, you need an extractor. If you catch yourself copying a value by hand from one response into the plan, stop: that value will be different on the next run, and for every user.

2Why We Need Extraction: Dynamic Values and Correlation

Real journeys are full of values that nobody can know in advance.

A recorded or hand-written test often works on the first try with one user and then fails as soon as it runs again. The reason is almost always the same: some values in the recorded requests were created by the server during that session and are no longer valid. Replacing such values with fresh ones taken from live replies is called correlation. The JSON Extractor is the main tool for correlation in API tests.

Value 1

Session and access tokens

Issued at log-in and sent with every later request. Different for each user, and often valid only for a limited time.

Value 2

Identifiers of created items

The number or code of a new order, cart, customer or document. Later steps read, change or delete it by that identifier.

Value 3

Anti-forgery and state values

Hidden values that the server expects to see again in the next request, to prove the request belongs to the same journey.

Value 4

Links and page markers

Addresses of the next page of results, or of a related resource, supplied inside the reply for the client to follow.

Value 5

Job and transaction references

Identifiers of long-running work that the client must check later, such as a report being generated.

Value 6

Items picked from lists

A product chosen from search results, whose identifier is then used to add it to a cart.

What happens without correlation

If you hard-code a token from one run, the second run is rejected as unauthorised. If you hard-code an order number, every virtual user fights over the same order, or the server reports that it does not exist. Under load, the symptoms get worse: hundreds of users updating one item produce locks, conflicts and unrealistic cache hits. The test then measures how the system copes with a strange, unnatural pattern, not with real users.

Example: the test that worked exactly once

A team recorded a shopping journey and replayed it with fifty users. Every user tried to add the same product to the same cart identifier that was captured during recording. The server answered with a conflict for almost all users after the first. Replacing the fixed identifier with a value extracted from the cart creation reply gave each user their own cart, and the errors disappeared.

!
Common Mistake

Treating a test as correct because it passed once with one user. A single run cannot reveal values that should have been different for each user. Always run with several users and different data before trusting a plan.

3The Extractor Family and Where the JSON Extractor Fits

JMeter offers several extractors. The best one depends on the format of the reply.

Extractors all do the same kind of job: read something from a response and store it in a variable. They differ in the language they use to point at the value. Choosing the one that matches the format of the reply gives simpler, faster and more reliable plans.

ExtractorBest used forWeakness
JSON ExtractorJSON replies, with paths that follow the structureNeeds valid JSON, and reads the body or a variable
JSON JMESPath ExtractorJSON replies where calculation, filtering or reshaping is neededA second path language to learn
Regular Expression ExtractorAny text, including headers, and replies of unknown formatBrittle on JSON, because it ignores structure
Boundary ExtractorValues between two known pieces of text, without pattern syntaxAlso ignores structure, and depends on stable surrounding text
XPath ExtractorStructured markup repliesNot for JSON
CSS Selector ExtractorValues in web page markupNot for JSON
Script-based extractionComplex logic over the responseCosts CPU, harder to maintain

Why not just use a pattern?

Many beginners reach for the regular expression extractor out of habit, because it works on any text. On JSON it is risky. A pattern that finds the text after the word “token” breaks if the field order changes, if spaces are added, or if the same word appears elsewhere in the reply. A JSON path follows the structure instead of the text, so layout changes do not matter, and it points at exactly one field. For JSON replies, the JSON Extractor is almost always the right choice.

Simple Analogy

A text pattern is like searching a printed book for the words “chapter three” and reading what follows. A JSON path is like opening the contents page, going to chapter three, and reading the title there. The second method still works when the book is reprinted with a different layout.

i
Practical Tip

Use a regular expression only when the value is not inside JSON, for example when it sits in a response header or a plain text reply. The JSON Extractor reads the body, so header values need another tool.

4Execution Order and Scope of the Extractor

When the extractor runs decides what it can see, and where it sits decides what it touches.

JMeter runs the elements around a request in a fixed order: configuration elements, pre-processors, timers, the sampler, post-processors, assertions and listeners. The JSON Extractor is a post-processor, so it runs after the response has arrived and before assertions. This is important for two reasons. The extractor can only see the response of the sampler it belongs to. And the values it stores are ready before the next sampler starts, so the next request can use them at once.

flowchart TD
    A["Sampler sends the request and receives the reply"] --> B["JSON Extractor follows the path and stores the value"]
    B --> C["Assertions check the reply"]
    C --> D["Listeners record the result"]
    D --> E["Next sampler starts and can use the stored variable"]
        
FIG 1 — The extractor runs after the reply and before the next request

Scope: which samplers the extractor serves

An extractor works on the samplers in its scope. As a child of a single sampler, it works only on that sampler. As a child of a controller or a thread group, it works on every sampler below. A broad extractor is convenient for a value that appears in every reply, but it also runs on replies that do not have the value, where it finds nothing and stores the default. Narrow scope is usually the safer choice.

PlacementRuns afterTypical use
Child of one samplerOnly that samplerAlmost every extraction, such as the token from the login reply
Inside a controllerEvery sampler in that controllerA value that appears in all replies of a business step
At thread group levelEvery sampler of the groupRare, for a value present in every reply
!
Common Mistake

Placing the extractor at the thread group level so that it runs after every request. On replies without the field it overwrites the variable with the default value, and a good token from the login step is destroyed by the next request. Keep each extractor next to the sampler that produces the value.

i
Practical Tip

Name each extractor after what it captures and where, such as “Token from login” or “Order id from create”. When something breaks, these names appear in logs and make the cause obvious.

5JSON and Path Basics in Plain Words

A short refresher that makes every later chapter easier.

JSON describes data using only a few ideas. An object is a group of named fields, like a form. An array is an ordered list of items, like the lines on a receipt. A value is text in quotation marks, a number, true or false, the empty value called null, or another object or array. Objects and arrays can be nested inside each other to any depth.

flowchart TD
    R["Root object: the whole reply"] --> T["Field: token"]
    R --> U["Field: user, an object"]
    U --> UI["Field: id"]
    U --> UN["Field: name"]
    R --> O["Field: orders, an array"]
    O --> O1["Item 1: id, total"]
    O --> O2["Item 2: id, total"]
        
FIG 2 — A reply seen as a tree: the path walks down this tree to one value

The building blocks of a path

A JSON path starts at the root, written as a dollar sign, and walks down by naming fields separated by dots. Square brackets pick items from arrays, counting from zero. A star selects every item, two dots search at any depth, and a filter in brackets keeps only the items that satisfy a condition.

Building blockWritten asMeaning
Root$The whole reply, where every path starts
Child field$.tokenThe field named token directly under the root
Nested field$.user.idThe id inside the user object
Array item$.orders[0].idThe id of the first order, counting from zero
All items$.orders[*].idThe id of every order
Search at any depth$..idEvery field named id, wherever it appears
Filter$.orders[?(@.total > 100)].idThe id of orders whose total is above one hundred
Simple Analogy

A path is like a postal address that gets more exact with each part: country, city, street, house number. Each step narrows the search until you reach one door. A wrong or missing step means the postman finds nothing.

!
Common Mistake

Counting array positions from one. The first item is position zero. A path that asks for position one returns the second item, or nothing on a short list, and the extractor quietly stores the default value.

6Definite and Indefinite Paths: One Answer or Many

The shape of your path decides whether you get one value or a list of values.

A path is called definite when it can point to at most one value. It names fields and exact array positions, nothing more. A path is called indefinite when it may match several values. It uses a star, a search at any depth, a filter, or a range of positions. This difference is small to read but large in effect, because it controls what the extractor stores and how the Match No. setting behaves.

KindExampleWhat you getWhen to use it
Definite$.data.tokenOne value, or nothingTokens, identifiers, single settings
Definite with position$.items[0].idOne value from a fixed placeWhen the first item is always the one you need
Indefinite with star$.items[*].idA list of valuesLoops, random choice, counting
Indefinite with search$..priceEvery price at any depthQuick exploration, not stable tests
Indefinite with filter$.items[?(@.stock > 0)].idOnly items that meet a ruleChoosing only valid, available items

Why the difference matters

With a definite path, the Match No. setting has little to decide, because there is only one candidate. With an indefinite path, Match No. becomes the main control. It tells the extractor whether to keep the first match, a random match, a specific numbered match, or all of them. Many beginner problems come from using an indefinite path and forgetting that the result is a list.

Simple Analogy

Asking for “the passport of the person named in seat 12A” is a definite request. You get one passport or none. Asking for “the passports of everyone on the plane” is indefinite. You must decide whether you want the first one, a random one, or the whole stack.

Choosing the narrowest path that works

Prefer the narrowest path that clearly points to what you need. A path such as $.data.token is easy to read and cheap to run. A path such as $..token searches the whole document and may match unrelated fields that happen to share the name. Narrow paths fail loudly when the structure changes, which is exactly what you want from a test.

i
Practical Tip

Use the search form with two dots only while exploring a new reply. Once you know where the field lives, replace it with the exact path. Exact paths are faster, safer and easier for teammates to understand.

!
Common Mistake

Using a filter on a field that is missing from some items and assuming every item is checked. Items without the field are simply skipped, so the result may be shorter than you expected without any warning.

Example: the wrong price

A tester used the search form to read a price from a product reply. The reply also held a shipping price and a discount price with the same field name. The extractor stored the first match, which was the shipping price. Cart totals in later steps were wrong for weeks. Switching to the exact path fixed it in one minute.

7The Fields of the JSON Extractor Element, One by One

Every box on the screen has a job. Knowing each one removes guesswork.

The element has a small number of fields. Each one is simple on its own, but the fields work together, and a small mistake in one of them changes the result of the others. Here is every field explained in plain words.

Field

Name

A label for the element. Choose a clear name such as “Extract token from login”. Names appear in logs and make large plans readable.

Field

Apply to

Chooses what the extractor reads: the main request and its sub-requests, only the main request, only the sub-requests, or a JMeter variable. Most of the time the main request is correct.

Field

Names of created variables

The names under which values are stored. For several paths, separate the names with semicolons. These names are what you use later.

Field

JSON Path expressions

The paths to read, also separated by semicolons. The first name pairs with the first path, the second with the second, and so on.

Field

Match No.

Decides which match to keep when a path finds several. Zero means random, a positive number means that numbered match, and minus one means all matches.

Field

Compute concatenation var

When ticked, creates an extra variable with all matches joined by commas. It is useful for compact lists.

Field

Default Values

What each variable holds when nothing is found. Also separated by semicolons and paired by position.

The pairing rule

The three list fields, names, paths and defaults, are paired by position. The first item of each belongs together. If you give three names and two paths, the third name has nothing to read. If you give two defaults for three names, the last variable gets no safe fallback. Always keep the three lists the same length and in the same order.

flowchart LR
    N["Names: token ; userId ; role"] --> P1["Pair 1: token"]
    J["Paths: $.token ; $.user.id ; $.user.role"] --> P1
    D["Defaults: NO_TOKEN ; NO_USER ; NO_ROLE"] --> P1
    P1 --> V["Variables token, userId, role"]
        
FIG 3 — Names, paths and defaults are paired by position
Simple Analogy

Think of three columns in a spreadsheet: the label, the cell address and the backup value. Row one in every column belongs to the same entry. If the columns have different lengths, the rows no longer line up and the wrong backup lands next to the wrong label.

!
Common Mistake

Leaving a space after a semicolon or around a name. A hidden space becomes part of the variable name, and later references fail to find it. Type the lists without extra spaces and check the names in a debug view.

8Match No. Explained: First, Random, Specific and All

One small number decides how a list of matches becomes variables.

When a path finds more than one value, the extractor needs a rule. The Match No. field is that rule. It is one of the most important settings in the element, and it is also one of the easiest to misread. Here are the choices.

Match No.MeaningVariables you getTypical use
1The first matchOne variable with the first valueThe newest item, the first result
2, 3, and so onThat numbered matchOne variable with that valueA fixed position, such as the second item
0A random matchOne variable with a randomly chosen valuePicking a random product or user
-1All matchesA count variable plus one numbered variable per matchLoops over every item

Why random is useful

Real users do not all buy the same product. If every virtual user opens the first item, the test hits the same database rows and the same cache entries, which makes results look better than reality. Choosing a random match spreads the load across the data, which is closer to real behaviour.

Why all is powerful

With minus one, the extractor stores every match as a numbered variable and also stores how many it found. That count lets a loop walk through the list. This is the base of many realistic journeys, such as opening every product on a search page or deleting every item in a basket.

Simple Analogy

A box of numbered raffle tickets. You can take the first ticket, pull one blindly, ask for ticket number five, or empty the whole box onto the table. Match No. is the instruction you give to the person holding the box.

i
Practical Tip

If a path is definite, keep Match No. at one. Only change it when the path is indefinite and you have a clear reason. A clear setting is a readable setting.

!
Common Mistake

Using random selection in a test that must be repeatable, such as a functional smoke check. Random choices make failures hard to reproduce. Use fixed positions for checks and random positions for load.

Example: the hot product problem

A load test always opened the first search result. Response times looked excellent because that product was cached everywhere. After switching to a random match, the same service showed slow replies for the long tail of products, which is what real shoppers experienced on busy days.

9The Variables the Extractor Creates

One extraction can leave several variables behind. Knowing their names avoids confusion.

For a variable name such as itemId, the extractor can create several related variables. Which ones appear depends on Match No. and on the concatenation option. The table below lists them.

VariableHoldsWhen it exists
itemIdThe chosen value, or the default when nothing matchedAlways, for a single match choice
itemId_matchNrHow many matches were foundAlways created, and used mainly with all matches
itemId_1, itemId_2, …The first match, the second match, and so onWhen Match No. is minus one
itemId_ALLAll matches joined with commasWhen concatenation is ticked

Reading the count

The count variable is the quiet hero. It tells you whether anything was found at all. A count of zero means the path matched nothing, even if the main variable holds a default. A loop uses it as the upper limit, and an assertion or an If Controller can use it to branch the journey.

Leftover variables from earlier runs

Numbered variables from a previous iteration can survive when the new reply is shorter. If the first reply had five items and the second only three, positions four and five may still hold old values unless the extractor clears them. Always trust the count, not the existence of a numbered variable.

flowchart TD
    A["Path finds 3 values"] --> B{"Match No."}
    B -->|"1"| C["itemId = first value"]
    B -->|"0"| D["itemId = random value"]
    B -->|"-1"| E["itemId_1, itemId_2, itemId_3 and itemId_matchNr = 3"]
    E --> F["Optional itemId_ALL = joined list"]
        
FIG 4 — The variables that appear for each Match No. choice
Simple Analogy

A shopping receipt shows each item on its own line and a final line with the number of items. The count line tells you how many lines to read. If you ignore it and read past the end, you may read the previous customer’s receipt.

i
Practical Tip

Keep names short, lower camel case and meaningful, such as orderId or productIds. Avoid names that end in an underscore and a number, because they can clash with the numbered variables the extractor creates.

10Default Values: Your Safety Net When Nothing Matches

A good default turns a silent problem into a visible one.

If the path finds nothing, the extractor stores the default value. If you leave the default empty, the variable may not be set at all, or may keep an old value from a previous iteration. Both cases are dangerous, because the next request then sends something wrong, and the failure appears far from its cause.

Choose obviously fake defaults

A good default is easy to spot in logs and impossible to confuse with real data. Values such as NOT_FOUND, NO_TOKEN or MISSING_ORDER_ID are clear. A default such as zero or one looks like a real identifier, and the server may even answer normally for it, which hides the problem completely.

Good defaults

  • Stand out in logs and reports
  • Cause a clear failure on the next request
  • Make assertions easy to write
  • Show exactly which extraction failed

Bad defaults

  • Look like real values such as 0 or 1
  • Leave the variable empty
  • Allow stale values to survive
  • Hide the failure until much later

Guarding the next step

A default value alone does not stop the journey. Add a check that fails fast when the default appears. A response assertion on the extractor’s own request, or an If Controller that skips dependent steps when the variable equals the default, keeps the test honest and the results clean.

Simple Analogy

A courier who cannot read an address should write “ADDRESS UNREADABLE” on the parcel, not copy the last address from memory. The first is a clear signal. The second sends the parcel to a stranger and nobody knows why.

!
Common Mistake

Leaving the default field empty because “the path always works”. It works until the day a service changes or fails, and that is the day you most need a clear signal.

Example: the stale basket

A test extracted a basket identifier after each login. When the login service slowed down and returned errors, no new identifier was found, and the old one from the previous iteration stayed in the variable. For an hour the test kept writing to a basket that had already been closed, and the error rate looked like a basket problem instead of a login problem.

11Several Variables in One Element and the Apply To Setting

One extractor can read many fields, and it can read from different sources.

You do not need a separate extractor for every value. A single element can read several fields from the same reply. This keeps the plan compact and makes it easier to see everything that one request produces. The rule is simple: give a list of names, a list of paths and a list of defaults, all separated by semicolons and all in the same order.

When to group and when to split

Group values that come from the same reply and serve the same purpose, such as the token and the user identifier from a login. Split values when they have different match rules, for example one random product and the full list of all products. Because Match No. and the concatenation option apply to the whole element, values that need different settings belong in different elements.

SituationGroup or splitReason
Token, user id and role from loginGroupSame reply, same single-match rule
One random product and all product idsSplitDifferent Match No. needs
Values with different default policiesSplitEasier to read and maintain
Twenty unrelated fieldsSplit by purposeOne huge element is hard to review

The Apply to setting

Most of the time the extractor reads the response of the request it belongs to. The Apply to field changes this. A request may have sub-requests, for example embedded resources fetched after a page. You can choose to read only the main reply, only the sub-replies, or both. You can also tell the extractor to read a JMeter variable instead of a reply. That last option is helpful when a value was already stored and holds a JSON text that you want to dig into further.

Option

Main sample and sub-samples

The default. Reads the main reply and any sub-replies. Fine when there are no sub-requests.

Option

Main sample only

The safest choice for API tests. It avoids reading unrelated sub-replies.

Option

Sub-samples only

For rare cases where the useful data is in an embedded request.

Option

JMeter variable

Reads a stored variable by name. Useful for second-level extraction.

Simple Analogy

Imagine a filing clerk with a parcel that contains one big envelope and several small ones. “Apply to” tells the clerk whether to open only the big envelope, only the small ones, both, or to read a note you already copied onto a card.

i
Practical Tip

For API work, choose “main sample only” unless you have a reason not to. It makes the source of every value clear and prevents surprises from sub-replies.

12What Gets Stored: Values Are Always Text

JMeter variables hold text. Understanding this prevents many small surprises.

Whatever the extractor finds, the stored variable is text. A number in the reply becomes the text of that number. A true or false value becomes the words true or false. This is fine for most uses, because later requests are text anyway. It matters when you do arithmetic or compare values, because you must convert the text back to a number in that step.

Kind of value in the replyWhat the variable holdsCare needed
TextThe text itselfQuotes are not part of the stored value
NumberThe digits as textLarge or decimal numbers may show a different format than the raw reply
True or falseThe word true or falseCompare as text
NullDepends on the version and the pathTreat as a special case and test it
ObjectThe object written back as JSON textCan be large, and spacing may differ from the original
ArrayThe array written back as JSON textUse a deeper path if you need single items

Objects and arrays as text

If the path points to an object or an array, the stored variable contains a JSON text of that part. This is useful when you want to pass a whole block to the next request, such as an address object copied from one reply into a new order. It is also a way to cut a big reply into smaller pieces for later extractors. Keep in mind that the text may be formatted differently from the original, so do not compare it character by character with the raw reply.

Numbers and formats

Very large identifiers and decimals can look different after being parsed and written back. If an identifier is a long number, check it in a debug view and, if the format changes, ask the service owners whether the field should be a text field. Silent changes in digits are rare, but they are painful to find.

Simple Analogy

A photocopier copies everything as a picture of the page, never as the original object. A copied banknote is a picture of a banknote. In the same way, every extracted value is a text copy of the original value, which is fine for passing along and not fine for spending.

!
Common Mistake

Assuming a stored null looks the same in every version, or that an empty text means the field was missing. A field that exists with an empty value and a field that is missing are different situations. Test both with a real reply and decide how your plan should treat each.

i
Practical Tip

When you need to compare a number, wrap the variable in a small calculation in a later step, and keep the original text variable untouched. This keeps your plan readable and avoids hidden conversions.

13Using Extracted Values in Later Requests

Extraction is only half the job. The other half is using the value in the right place.

Once a variable exists, you use it by writing its name inside a dollar sign and curly braces in any later field. That includes the path of a request, a query parameter, a header, a request body, an assertion or even another extractor. JMeter replaces the placeholder with the stored text just before sending.

Where

Request path

Resource identifiers often sit in the path, such as the order to open or delete.

Where

Query parameters

Search terms, page tokens and filters travel here.

Where

Headers

Access tokens go into an authorization header. A header manager at plan level can apply it to every request.

Where

Request body

Identifiers and copied blocks are placed inside the JSON body of create and update calls.

Where

Assertions

Echo checks compare a reply field with the variable you sent.

Where

Controllers and timers

Conditions and loop counts may use the count variable and the values.

Scope: who can see the variable

A variable belongs to the virtual user that created it. Another virtual user cannot see it. This is a good thing, because each user gets their own token and their own order identifier. It also means a value extracted in one thread group cannot be read in another thread group directly. If you need to share a value across groups, a property is the usual route, and it needs care, which a later chapter explains.

Order of use

The extractor runs after its own request, so its variable is ready for the next request in the sequence. It is not ready for the same request, because that request has already been sent. If a value is needed in the very first request, it must come from somewhere earlier, such as a data file or a setup step.

sequenceDiagram
    participant U as Virtual user
    participant S as Server
    U->>S: Request 1, login
    S-->>U: Reply with token
    Note over U: Extractor stores token
    U->>S: Request 2 sends stored token
    S-->>U: Reply for that user
        
FIG 5 — The extracted value travels from one reply into the next request
Simple Analogy

A hotel desk gives you a key card at check-in. The card is yours alone, and every door you visit later reads it. The card cannot open the door that issued it before you received it, because you did not have it yet.

!
Common Mistake

Using a variable in a field that is evaluated before the extractor runs, for example in a setup step that executes only once, expecting a per-iteration value. Check where each value is born and where it is used.

14A Chaining Walkthrough: Log In, Create, Read and Delete

A realistic story shows how each extractor feeds the next request.

Let us follow a simple but typical journey for a task management service. The user logs in, creates a task, reads the task back, and deletes it. Three values travel between steps: the access token, the new task identifier and, for checking, the title of the task. Each step has an extractor that prepares the next one.

1

Log in

The reply holds an access token. An extractor stores it under the name token, with a default of NO_TOKEN. An assertion confirms the token path exists.

2

Create a task

The request sends the token in a header and a generated title in the body. The reply holds the new task identifier. An extractor stores it as taskId, with a default of NO_TASK.

3

Read the task

The request uses taskId in its path. An echo assertion checks that the reply carries the same identifier and the same title that were sent.

4

Delete the task

The request uses taskId again. The reply should confirm the deletion, and an assertion checks the confirmation field.

flowchart LR
    A["Login"] -->|"token"| B["Create task"]
    B -->|"taskId"| C["Read task"]
    C -->|"taskId"| D["Delete task"]
    A -.->|"token in header"| C
    A -.->|"token in header"| D
        
FIG 6 — Values flowing along a four-step journey

What this teaches

Every arrow in the picture is an extraction on the sending side and a use on the receiving side. When something fails, you can follow the arrows backward. If the delete step fails with a missing identifier, you look at the create step’s extractor. If every step fails, you look at the login. This makes problems small and local, which is the whole point of designing journeys as chains.

i
Practical Tip

Name steps with numbers and verbs, such as “01 Login”, “02 Create task”. Reports sort neatly, and a failing step tells its story at a glance.

Example: cleaning up after yourself

A team created ten thousand tasks per hour during a load test and never deleted them. After a night the database was full and the next morning’s tests began failing. Adding the delete step, fed by the same identifier extractor, kept the data size stable and the results comparable between runs.

15Looping Over Extracted Lists with the ForEach Controller

When you extract all matches, a loop lets you act on each of them.

Suppose a search reply contains twenty product identifiers and your user should open each one. The extractor, with Match No. set to minus one, creates numbered variables and a count. The ForEach Controller then walks through those numbered variables one by one, running its child requests each time with the current value ready.

The fields that matter

FieldWhat to enterDetail
Input variable prefixThe extractor variable name, such as productIdThe controller looks for productId_1, productId_2 and so on
Start index for loopZero to start at the first itemThe index is exclusive, so zero means the loop begins at item one
End index for loopThe count, or a number you chooseThe end index is inclusive, so the count includes the last item
Output variable nameThe name each child request uses, such as currentProductThe current value is placed here on each turn
Add an underscore before numberTick itMatches the underscore in the numbered variable names

Limiting the loop

Real shoppers do not open every item. If a search returns a hundred products, you may want only the first five. Set the end index to a small number and keep the count as a safety limit. Be careful that the end index does not exceed the real count, because the loop would then read variables that do not exist and send placeholder text to the server.

flowchart TD
    A["Search request"] --> B["Extractor, Match No. -1: productId_1 ... productId_N and count"]
    B --> C["ForEach Controller: prefix productId"]
    C --> D["Open product request uses current value"]
    D --> C
    C --> E["Loop ends, continue to checkout"]
        
FIG 7 — Extract all, then loop through each item
Simple Analogy

A teacher with a numbered class list calls name one, name two, name three, until the list ends. The count tells the teacher where the list stops, and the underscore-number pattern is the numbering on the list.

!
Common Mistake

Forgetting that the start index is exclusive. Setting it to one skips the first item. Set it to zero to begin at the first match.

i
Practical Tip

Add a small think time inside the loop, so the virtual user behaves like a person reading each page, not like a machine firing requests as fast as it can.

16Pagination and Polling: Extracting Inside a While Loop

Some journeys do not know in advance how many steps they need. The reply decides.

Two common situations need a loop that depends on a reply. The first is pagination. A service returns a list in pages, and each reply carries a marker that points to the next page. The second is polling. A service starts a job in the background, and the user must ask again and again until the job is done. In both cases an extractor reads a field from the reply, and a loop condition uses that field to decide whether to continue.

Pagination step by step

The first request asks for the first page. The extractor stores the next-page marker, with a default that means “no more pages”, for example an empty marker that the loop condition understands. The loop condition checks the variable. While a marker exists, the loop runs the next page request using the marker. When the reply no longer contains a marker, the extractor stores the default, the condition becomes false, and the loop ends.

flowchart TD
    A["First page request"] --> B["Extractor reads next marker, default is empty"]
    B --> C{"Marker has a value?"}
    C -->|"Yes"| D["Request next page with marker"]
    D --> B
    C -->|"No"| E["Loop ends"]
        
FIG 8 — A loop that follows page markers until none is left

Polling step by step

Polling is similar. The start request returns a job identifier. A loop then calls the status request. The extractor reads the status field, and the loop continues while the status says the job is still running. A short pause between calls prevents hammering the service. When the status says done or failed, the loop ends, and an assertion checks that the final status is the expected one.

Loop typeValue extractedContinue whileSafety limit
PaginationNext page markerThe marker has a real valueA maximum number of pages
PollingJob statusThe status is still runningA maximum wait time or attempt count
Retry on pendingA ready flagThe flag is not yet trueA maximum number of retries

Always add a safety limit

A loop that depends only on a reply can run forever if the reply never changes. A bug in the service, a wrong path in your extractor, or a default that equals a real value would trap your virtual user inside the loop. Add a second condition, such as a counter that stops the loop after a fixed number of rounds. Treat reaching that limit as a test failure, because the journey did not complete in a reasonable time.

Simple Analogy

Reading a book with a bookmark in each chapter that says “continue on page so-and-so” is pagination. Waiting at a bakery counter and asking “is my bread ready yet?” every minute is polling. In both cases a sensible person gives up after a long time instead of waiting for ever.

!
Common Mistake

Choosing a default value that matches a real status, such as the word running. If the extractor fails, the default says “still running”, and the loop spins until the safety limit, or for ever without one. Use a clearly different default and handle it as an error.

Example: the export that never ended

A report export took between ten and sixty seconds. The test polled once per second with no limit. When a bug made the job stall, a hundred virtual users sat in the loop for the full test hour, sending millions of status calls. Adding a limit of ninety attempts and treating the limit as a failure turned a hidden disaster into a clear red line on the chart.

17Random Selection for Realistic Load

Real users choose different things. Your extractor can imitate that.

Load tests are only as honest as the data they use. If every virtual user opens the same product, edits the same record, or searches the same word, caches and databases behave in a way that real traffic never would. The extractor’s random mode helps by choosing one match at random from a list that the server just provided. Because the list comes from the server, every choice is valid at that moment.

Where random choice helps

Use

Random product

Search, pick a random result and open it. This spreads reads across the catalogue.

Use

Random available slot

For booking systems, choose any free slot from a filtered list, so the test does not try the same slot every time.

Use

Random category

Read the list of categories, choose one, and browse it. Each user follows a different path.

Use

Random existing user

For admin tests, choose any user from a returned page to view or edit.

Combining random choice with filters

A random pick from an unfiltered list may select an item that cannot be used, such as a product that is out of stock. A filter inside the path removes those items before the random choice happens. In this way the extractor only draws from valid candidates, and your later requests rarely fail for business reasons that have nothing to do with performance.

flowchart LR
    A["Server returns 40 products"] --> B["Path filter keeps 25 in-stock products"]
    B --> C["Match No. 0 picks one at random"]
    C --> D["Variable productId holds the chosen value"]
    D --> E["Next request opens that product"]
        
FIG 9 — Filter first, then choose at random

Weighing randomness against repeatability

Random choices make a run differ from the previous one. For comparing two builds, differences that come from random picks can look like differences in the product. Two habits reduce this problem. Use large enough runs, so that the randomness averages out. And log the chosen values in a debug view during a small trial, so you can reproduce a surprising failure by feeding the same value manually.

Simple Analogy

A restaurant inspector who always tastes the first dish on the menu learns little. One who chooses dishes at random, from the dishes that are actually being served today, gets a fair picture of the kitchen.

i
Practical Tip

Record the chosen identifier in the request name or a log field for failed requests. When a single random item causes a slow or failing reply, you will know which item to investigate.

!
Common Mistake

Using random choice and then asserting a fixed expected value. The expected value must come from the same chosen item, usually through the variable, not from a hard-coded example.

18Token Lifecycle: Logins, Expiry and Refresh

Tokens are the most common extracted value, and the most common source of long-run failures.

Most modern services give a short-lived token after login. Every later request carries it. The extractor captures it once, and a header manager sends it on each call. This pattern is simple for a two-minute test, and it becomes interesting in a two-hour test, because tokens expire. If the test ignores expiry, the second half of the run fails with authorization errors that say nothing about the performance of the service.

Three ways to handle expiry

ApproachHow it worksGood whenCare needed
Log in each iterationEvery loop begins with a login and a fresh extractionJourneys are short and login is part of real behaviourAdds load to the login service
Refresh on a scheduleA refresh call runs before the token’s lifetime endsLong journeys with one loginNeeds the expiry time and a second extraction of the new token
React to an authorization failureOn an unauthorized reply, the plan logs in again and retries onceExpiry times are unpredictableRisk of retry storms if the login itself fails

Capturing the expiry too

Many services return the token and a lifetime in seconds, or an expiry time. Extract both with one element. A small calculation can then store the time at which a refresh is due, and an If Controller can compare it with the current time before each request. This keeps the test running smoothly for hours, and it mirrors how real clients behave.

flowchart TD
    A["Login, extract token and lifetime"] --> B["Work requests with token"]
    B --> C{"Token close to expiry?"}
    C -->|"No"| B
    C -->|"Yes"| D["Refresh call, extract new token"]
    D --> B
        
FIG 10 — A journey that refreshes its token before it expires

A shared token for everyone

Sometimes a test uses one token for all virtual users, for example a service account. This is simpler, and it is also less realistic, because the server sees one identity with a very high request rate and may throttle it. If the real system has many users, the test should use many tokens, one per virtual user, each captured by its own login.

Simple Analogy

A day pass at an amusement park stops working at closing time. A visitor who stays until evening needs a new pass, or a renewal at the gate. A clever visitor renews before the gates close rather than being stopped halfway on a ride queue.

!
Common Mistake

Counting authorization errors from an expired token as service failures in the report. They are test design failures. Separate them with an assertion that names the cause, so that the performance numbers stay trustworthy.

i
Practical Tip

Set a test duration that is longer than the token lifetime during your pilot run. If nothing breaks, your expiry handling works. If it breaks, you found the problem on a quiet day.

19Pairing the Extractor with the JSON Assertion

The extractor takes a value. The assertion proves the value was worth taking.

An extractor and an assertion often read the same path, and they have different jobs. The extractor stores a value for later. The assertion says whether the reply was correct. If you use only the extractor, a failed extraction quietly stores the default and the problem appears later. If you add an assertion on the same path, the failure appears on the request that caused it, with a clear name.

QuestionExtractorJSON Assertion
Main jobSave a value for later useDecide pass or fail for this reply
If the path finds nothingStores the default and the request still passesMarks the request as failed with a message
Changes the reportNo, unless a later step failsYes, failures appear in error rates
Best placementUnder the request that produces the valueUnder the same request, after the extractor

The standard pairing

For every value you extract and later depend on, add an existence check on the same path. For identifiers, this is usually enough. For values that must have a meaning, such as a status, add an equals check as well. With this pair in place, a missing token, an empty list, or a changed field name stops the journey early at the exact request that produced it.

Pair

Token

Extract the token. Assert that the token path exists.

Pair

Created identifier

Extract the new identifier. Assert it exists and, if the format is known, that it has the expected shape.

Pair

List of items

Extract all identifiers. Assert that the first item exists, so an empty list is a visible failure.

Pair

Status flag

Extract the status for loops. Assert the final value after the loop ends.

Why not just rely on the default?

A default can only protect the next request. It cannot tell the report that this request, the one that should have returned the value, was the real culprit. The assertion gives the failure a home. The result is shorter investigations, cleaner error counts and fewer arguments about whether a failure belongs to the test or the system.

Simple Analogy

A cashier takes your note and puts it in the till, which is the extractor. A second person checks whether the note is genuine, which is the assertion. A till full of notes is no help if nobody checks them, and a checker with no till has nowhere to put the good notes.

i
Practical Tip

Order matters inside one request. Place the extractor first and the assertion after it, and give both names that mention the field. Failure messages then read like a sentence.

!
Common Mistake

Writing the path twice by hand and letting the two drift apart after a service change. Keep a short note of where each path is used, and update both together.

20Testing and Debugging Your Extractor

A few simple tools show exactly what the extractor saw and what it stored.

An extractor that has not been tested on real data is only a guess. Fortunately, JMeter gives several ways to see what is happening. Use them every time you add or change an extractor, and again after any service change.

The tools you can use

1

View Results Tree with the JSON path tester

Run one request. In the results tree, choose the response and switch the display to the JSON path tester. Type your path and see the matches at once, without rerunning anything.

2

Debug Sampler

Add it after the request. It lists all variables and their current values in its own reply, so you can see what the extractor stored.

3

Debug PostProcessor

Attach it to a request to record variables and properties for that request in its sample details, which keeps the plan tidier.

4

The log

Extraction problems and invalid paths show as messages in the log viewer. Open it when a variable remains at its default.

A short routine for each new extractor

First, run the request once with a single thread and look at the real reply. Second, test the path in the path tester and confirm that it finds exactly what you expect, nothing more and nothing less. Third, add a debug view and confirm that the variable holds the right value. Fourth, break the path on purpose and confirm that the variable shows your obviously fake default. Finally, remove or disable the debug elements before a large run, because they cost memory and time.

flowchart LR
    A["Run one request"] --> B["Test path in the path tester"]
    B --> C["Check variable in a debug view"]
    C --> D["Break the path on purpose"]
    D --> E["Confirm the default appears"]
    E --> F["Disable debug elements for the real run"]
        
FIG 11 — A small routine that proves an extractor works and fails well
Simple Analogy

A new smoke alarm should be tested with a button press and then with a little smoke. Pressing the button proves the alarm sounds. A real test proves it senses a problem. An extractor needs both: the happy path and the deliberate break.

!
Common Mistake

Leaving a View Results Tree enabled during a large run. It stores every reply in memory and can slow down or crash the generator. Use it only for small trials and for failed requests.

i
Practical Tip

Copy a healthy reply and a broken reply into a notes file next to your plan. You can then test paths without a live system, which is perfect for quick reviews before a release.

21Alternatives and When to Choose Them

The JSON Extractor is a great default, but it is not the only tool in the box.

JMeter offers several ways to pull a value from a reply. The right one depends on the format of the reply and on how complex the rule is. For structured JSON replies, the JSON Extractor is almost always the clearest and most readable choice. For other formats, or for unusual rules, another tool may fit better. Knowing the options helps you choose without hesitation.

ToolBest forStrengthWeakness
JSON ExtractorJSON replies with clear structureReadable paths, filters, listsNeeds valid JSON
JSON JMESPath ExtractorJSON replies, in versions that include itPowerful query language with projectionsA second path language for the team to learn
Regular Expression ExtractorText, headers, odd or broken formatsWorks on anything that is textFragile when the text layout changes
Boundary ExtractorValues between two known text markersSimple and fastMarkers must be unique and stable
XPath ExtractorXML and HTML repliesStructure-aware for markupWrong tool for JSON
CSS Selector ExtractorHTML pagesFamiliar to web developersOnly for HTML
Script-based extractionComplex rules and calculationsUnlimited flexibilityHarder to read, test and keep fast

A simple decision path

If the reply is valid JSON, start with the JSON Extractor. If your rule needs a calculation, or the path language cannot express it, consider a script step, but keep it small. If the reply is not JSON, choose the tool made for that format. If a reply mixes formats, such as JSON inside a text line, extract the outer part first with a boundary or a pattern, and then use the JSON Extractor on the variable with the Apply to setting.

flowchart TD
    A["What is the reply format?"] --> B{"Valid JSON?"}
    B -->|"Yes"| C["JSON Extractor"]
    B -->|"No, XML or HTML"| D["XPath or CSS Selector Extractor"]
    B -->|"No, plain text or headers"| E["Boundary or Regular Expression Extractor"]
    B -->|"Mixed"| F["Cut out the JSON part first, then JSON Extractor on the variable"]
        
FIG 12 — Choosing the extractor by the format of the reply
Simple Analogy

A kitchen has a paring knife, a bread knife and a cleaver. You can cut a tomato with any of them, but the paring knife is quick, safe and clean. The JSON Extractor is the paring knife for JSON: right for most jobs, and not the tool for sawing bread.

i
Practical Tip

Avoid using a regular expression on JSON just because you know it well. A change in field order or spacing can silently break it, while a path stays correct as long as the structure stays the same.

!
Common Mistake

Writing a long script to do what one path can do. Scripts cost more CPU, hide logic from reviewers and are harder to maintain. Reach for them only when a built-in element cannot do the job.

22Performance Cost of Extraction

A small element repeated thousands of times per second is no longer small.

Every extraction reads the reply, parses it as a document, and evaluates a path. With one user this takes a tiny fraction of a millisecond. With hundreds of users and thousands of requests per second, the sum becomes visible in the CPU and memory of the load generator. If the generator is busy, it measures its own delay as response time, and your results become less trustworthy.

What drives the cost

Driver

Size of the reply

Bigger replies take longer to parse. A reply of several megabytes costs far more than one of a few kilobytes.

Driver

Number of paths

Each path is evaluated on the parsed document. Many paths on one large reply add up.

Driver

Path complexity

Searches at any depth and filters visit many nodes. Exact paths touch only a few.

Driver

Stored variable size

Extracting a big object into a variable keeps that text in memory for every virtual user.

Driver

Request rate

The same element running ten times more often costs ten times more.

Practical ways to keep the cost low

Extract only what a later step truly needs. Use exact paths instead of searches. Avoid storing whole objects when one field is enough. Remove extractors that nobody uses any more, which is common in plans that have grown over time. For big replies that you only need to pass along, think about whether the later request can ask the server for a smaller reply instead.

Measuring the effect

The honest way to know is to measure. Run the same test with the extractors enabled and disabled at a moderate load, and compare the CPU and memory of the generator and the response times. If the difference is small, you are safe. If it is large, trim the work or add more generator machines. Keep the CPU of a generator below a comfortable level, so that the timings stay a measure of the service, not of the tool.

ChoiceCheaper optionCostlier option
Path styleExact pathSearch at any depth
What to storeOne fieldA whole object or array
How many extractorsOnly those needed laterEverything just in case
Debug elementsDisabled in real runsLeft enabled for every sample
Simple Analogy

A mail room clerk who opens every letter completely, and copies out the whole text, works much slower than one who only reads the reference number on the top corner. Both can do the job, and only one can keep up when the mountain of letters arrives.

!
Common Mistake

Blaming the service for slow responses when the generator itself was overloaded. Always watch the generator’s CPU and memory during a run, and treat a high reading as a warning about the accuracy of the results.

23Distributed Tests, Threads and Properties

Where a variable lives decides who can see it. This matters more when many machines are involved.

In a distributed test, one controller machine sends the same plan to several worker machines. Each worker runs its own virtual users, and each virtual user has its own variables. A value extracted on one worker is not visible on another, and a value extracted by one user is not visible to another user. For most journeys this is exactly what you want, because each user logs in and works with their own data.

Variables and properties

ItemVisible toTypical useCare needed
VariableOne virtual userTokens, identifiers, per-user dataCannot be shared with other users
PropertyAll users on the same JMeter processShared settings such as a service account tokenNot shared across worker machines automatically

Sharing a value inside one machine

Sometimes a setup step logs in once, and every user should use that result. A property can carry it. A small script step copies the extracted variable into a property in the setup group, and the main group reads the property into a variable at the start. This pattern is useful, and it must be used with care. Properties are global to the process, so only one source should write them, and users should only read them.

Sharing across worker machines

Each worker runs the setup step itself, so each worker gets its own value. If the service requires a single shared token for the whole test, the setup values must be consistent, for example by giving the token through a command-line option to every worker. Otherwise, let each worker log in separately, which is simpler and often more realistic.

flowchart TD
    C["Controller sends the plan"] --> W1["Worker 1: own users, own variables"]
    C --> W2["Worker 2: own users, own variables"]
    W1 --> S1["Setup step: login, property on worker 1"]
    W2 --> S2["Setup step: login, property on worker 2"]
    S1 --> U1["Users on worker 1 read property"]
    S2 --> U2["Users on worker 2 read property"]
        
FIG 13 — Each worker has its own variables and its own properties
Simple Analogy

Each office branch of a company has its own notice board, which every employee in that branch can read, while each employee also has a private notebook. A note pinned in the London branch is invisible in the Paris branch unless someone sends it there on purpose.

!
Common Mistake

Expecting one worker’s extracted value to appear on another worker. The workers are separate processes, and nothing travels between them except what you send deliberately.

i
Practical Tip

Prefer per-user variables for per-user data. Reach for properties only for truly shared items, and name them clearly so nobody mistakes them for user data.

24Security and Privacy of Extracted Values

Extracted values are often secrets. Treat them as carefully as the real system would.

The values that testers extract are often the most sensitive ones in the whole exchange: access tokens, session identifiers, customer identifiers and sometimes personal data. Because JMeter stores variables in memory and can write them to files and reports, a careless setup spreads secrets to places where they do not belong.

Where secrets can leak

Risk

Saved result files

Result files that store request headers and response bodies may contain tokens and personal data. Store only what you need.

Risk

Extra variables in results

A setting can add chosen variables to every row of the result file. Never list a token variable there.

Risk

Debug views and logs

Debug elements print values. Screenshots and shared logs may then reveal them.

Risk

Assertion messages

Failure messages can include the value found. Keep sensitive values out of custom messages.

Risk

Shared plans and reports

Plan files saved with real tokens in default fields end up in repositories and tickets.

Good habits

Use dedicated test accounts and synthetic data, never real customer data. Use short-lived tokens, and rotate them. Keep real credentials out of plan files by reading them from protected sources at run time. Mask or remove values before sharing a report or a screenshot. Delete result files that contain secrets when the investigation ends, and apply the same retention rules your company uses for other sensitive files.

flowchart LR
    A["Token extracted into a variable"] --> B["Used in headers of later requests"]
    A --> C{"Where else might it go?"}
    C --> D["Result file"]
    C --> E["Debug view and logs"]
    C --> F["Failure messages"]
    C --> G["Saved plan defaults"]
    D --> H["Limit what is saved and mask before sharing"]
    E --> H
    F --> H
    G --> H
        
FIG 14 — Places where an extracted secret can travel
Simple Analogy

A hotel key card is harmless until someone photographs it, prints a copy and pins it on a public board. Extracting a token is like handing the key to a guest. The guest, and the hotel, are responsible for not leaving copies around.

!
Common Mistake

Pasting a screenshot of a debug view into a ticket without checking what it shows. A single visible token can be enough for someone to act as that user until it expires.

Example: the token in the ticket

A tester attached a result file to a public bug tracker. The file held the authorization header of every request. A security review spotted long-lived tokens in it, and the team had to rotate credentials for the whole test environment. Since then, the team saves only response times and error messages by default and masks the rest.

25Design Patterns for Reliable Extraction

A few reusable habits make extraction plans clean, fast to debug and easy to hand over.

“An extractor that cannot fail loudly is a trap waiting for the day the service changes.”

Patterns are proven answers to common problems. They save time, because you do not invent a new approach each time, and they help a team read each other’s plans. Here are the patterns that serve JSON extraction best.

PatternWhat it doesWhy it helps
Extract, assert, usePair each extractor with an existence check, then use the valueFailures appear at the request that caused them
Fake defaultsUse clearly fake default values such as NOT_FOUNDMakes failed extractions obvious in logs
Narrow pathsPrefer exact paths over searchesFaster and more stable
Filter then chooseFilter candidates in the path and choose randomly from the resultRealistic load with valid data
Count-guarded loopsLoop using the count variable and a safety limitLoops end, even when the service misbehaves
Setup then shareDo shared work once in a setup groupAvoids repeated work and extra load
Reuse through modulesKeep common login and extraction steps in one reusable blockOne place to fix when the service changes
Clean up after useDelete test data created by the journeyKeeps runs repeatable and the environment healthy

Naming conventions

Agree on a naming style and keep it. Short, meaningful, lower camel case names such as authToken, orderId and productIds are easy to read. Name elements by what they extract: “Extract authToken from login”. When someone reviews the plan a year later, the names tell the story without opening a single element.

A map of the plan

For larger plans, keep a one-page map listing every variable, where it is extracted, where it is used and what happens when it is missing. It takes an hour to create and saves days of confusion, especially when new people join the team or when the service changes its replies.

Simple Analogy

A well-run kitchen uses labels, standard containers and a written recipe. Anyone can step in, find the sauce and know what it contains. A plan with good patterns is a labelled kitchen: new cooks are productive on day one.

i
Practical Tip

Create a template journey with the extract, assert, use pattern already built in. Copy it for every new journey, and your plans start out with the right habits.

!
Common Mistake

Copying a login block into every thread group instead of reusing one shared block. When the login changes, you must hunt down every copy, and you will miss one.

26Anti-Patterns: Common Extraction Mistakes and How to Fix Them

These habits look harmless and cause long, confusing investigations.

An anti-pattern is a solution that seems reasonable and keeps causing trouble. Learning to recognise them is the fastest way to improve a plan. Each box below names the problem, explains the harm and shows the better way.

ANTI-PATTERN-01 Avoid
Problem

The default value field is left empty, or filled with a realistic value such as zero or one.

Why It’s Harmful

When extraction fails, the variable is empty, stale or looks real. Later requests send wrong data, sometimes receive normal answers, and the cause stays hidden for hours.

Correct Approach

Use clearly fake defaults such as NOT_FOUND, and add an assertion or a condition that fails fast when the default appears.

ANTI-PATTERN-02 Avoid
Problem

Paths that search the whole document, such as a double dot followed by a common field name, are used in stable tests.

Why It’s Harmful

The search can match unrelated fields with the same name, the first match may change when the service adds a field, and the cost grows with the size of the reply.

Correct Approach

Use exact paths in tests. Keep searches for the exploration phase only.

ANTI-PATTERN-03 Avoid
Problem

The extractor is the only guard. There is no assertion on the same path.

Why It’s Harmful

A failed extraction does not mark the request as failed. The error shows up two or three steps later, and the report blames the wrong request.

Correct Approach

Add an existence check beside every extractor whose value is needed later.

ANTI-PATTERN-04 Avoid
Problem

Loops that depend only on an extracted value, with no safety limit.

Why It’s Harmful

If the value never changes, virtual users stay inside the loop for ever, creating huge traffic and hiding the real problem.

Correct Approach

Add a counter-based limit and treat reaching it as a failure.

ANTI-PATTERN-05 Avoid
Problem

Extracting large objects and arrays into variables “just in case”.

Why It’s Harmful

Each virtual user keeps its own copy in memory, which multiplies cost, and the extra parsing slows the generator.

Correct Approach

Extract only the fields that later steps use, with exact paths.

ANTI-PATTERN-06 Avoid
Problem

Tokens are saved in result files, shown in debug views that are shared, or kept as real values in saved plans.

Why It’s Harmful

Secrets spread to tickets, repositories and chat messages. Anyone with access can act as that user while the token is valid.

Correct Approach

Use test accounts, short-lived tokens, limited saved data and masking before sharing anything.

i
Practical Tip

Review a plan against this list once a quarter. Most plans contain at least two of these mistakes, and fixing them takes less time than a single long investigation.

27Best Practices Checklist for Extractors

A short list you can follow every time you add an extractor to a plan.

Best practices are the habits of experienced testers, collected in one place. None of them is hard. Together they make plans that are faster to build, easier to read and much less likely to fail in mysterious ways.

1

Look at a real reply first

Run one request and read the reply before writing a path. Never guess the structure from documentation alone.

2

Write the narrowest exact path

Test it in the path tester and confirm it returns exactly what you expect.

3

Name variables and elements clearly

Use short, meaningful names, and keep the three lists of names, paths and defaults in the same order.

4

Set a fake default

Make failed extractions visible and impossible to confuse with real data.

5

Add an assertion on the same path

Make the failure appear on the request that caused it.

6

Choose Match No. on purpose

First for single values, random for realistic choice, all for loops, and a fixed position only when the position has meaning.

7

Break it on purpose

Confirm that the default appears and the assertion fails with a clear message.

8

Remove debug elements before a big run

They cost memory and time, and they can leak secrets.

Do

  • Test paths on real replies
  • Keep defaults obviously fake
  • Limit loops with counters
  • Use per-user variables for per-user data
  • Keep secrets out of reports

Do not

  • Guess paths from memory
  • Leave defaults empty
  • Loop on a reply with no limit
  • Extract whole objects without a reason
  • Share tokens in screenshots
Simple Analogy

A pilot reads a checklist before every flight, not because the pilot forgets how to fly, but because the checklist protects against the one step that is easy to skip on a busy day. The extractor checklist works the same way.

28Real-World Scenarios: Extraction in Typical Systems

Four common kinds of systems, and how the extractor supports each of them.

Ideas become clearer when we see them in familiar settings. Here are four systems that testers meet again and again, and the extraction needs of each.

Online shop

A shopper logs in and the extractor stores the token. A search reply returns a list of products, and a random match with an in-stock filter chooses one. The cart reply returns a cart identifier, which the checkout request needs. The order reply returns an order number, which the history request must contain. The chain has four extractions, each paired with an assertion, and the shop’s database sees a realistic spread of products.

Banking application

After login, the account list reply holds several account identifiers. A random match picks one account for balance and statement requests. A transfer request creates a reference, which the extractor stores so a later status request can confirm the transfer. Strict security rules apply, so the team masks tokens, uses synthetic accounts and limits what is saved in result files.

Ticket booking platform

A search returns events, and a filter keeps those with free seats. A random event is chosen, and its seat map returns available seats. The extractor picks a seat and a hold identifier. A short timer limits the hold, so the extractor and the following payment step must run quickly, and a polling loop watches the booking status until confirmation.

Data export service

A request starts a report and returns a job identifier. A polling loop reads the status with a capped number of attempts and a pause between them. When the status says done, the extractor reads a download link, and a final request fetches the file. The total time from start to download is measured as one transaction, which is what the business customer cares about.

SystemMain extracted valuesSpecial care
Online shopToken, product id, cart id, order idFilter to in-stock items before random choice
BankingToken, account id, transfer referenceMasking and synthetic data
Ticket bookingEvent id, seat id, hold idTime-limited holds and polling
Data exportJob id, status, download linkSafety limit on polling
i
Practical Tip

Draw your own system’s value chain on one page before building. Mark every value that moves from one reply to a later request. Each mark is an extractor, and each extractor is paired with an assertion.

29Troubleshooting: When the Variable Is Empty or Wrong

A calm, step-by-step approach finds the cause of most extraction problems in minutes.

When an extractor does not work, the symptom is usually the same: the variable holds the default value, holds an old value, or holds something unexpected. The cause is almost always one of a short list. Work through the list from top to bottom.

SymptomLikely causeWhat to check
Variable holds the defaultPath finds nothingTest the path in the path tester on the real reply
Variable holds the defaultReply is not valid JSON, such as an error pageRead the real reply and the status code
Variable holds the defaultWrong source in Apply toCheck whether the extractor should read the main reply or a variable
Variable is emptySpaces in the variable name or pathLook for hidden spaces around semicolons and names
Placeholder text appears in the next requestVariable name mismatchCompare spelling and case in the extractor and in the request
Old value appearsExtraction failed and the old value survivedSet a default and add an assertion
Loop reads strange valuesWrong start or end index, or leftover numbered variablesUse the count variable and remember that the start index is exclusive
Wrong value chosenPath matches several fieldsMake the path exact or add a filter
Works with one user, fails with manyVariable shared by mistake through a property, or rate limitsUse per-user variables and check server throttling

The five-question routine

flowchart TD
    A["Variable wrong or empty"] --> B{"Is the reply valid JSON?"}
    B -->|"No"| C["Fix the request or the environment first"]
    B -->|"Yes"| D{"Does the path find the value in the path tester?"}
    D -->|"No"| E["Correct the path"]
    D -->|"Yes"| F{"Do names, paths and defaults line up?"}
    F -->|"No"| G["Fix the lists, remove hidden spaces"]
    F -->|"Yes"| H{"Is the variable used after it is created?"}
    H -->|"No"| I["Reorder steps or move the extractor"]
    H -->|"Yes"| J["Check scope, properties and server limits"]
        
FIG 15 — A short path from symptom to cause

Most problems end at the first or second question. A reply that is not valid JSON is the single most common cause, because overloaded services often return an HTML error page with the same status code that the extractor expected to see on a good day. The path itself was fine, and the reply simply was not what you thought it was.

Simple Analogy

If a radio is silent, you first check whether it is plugged in and tuned, before opening the casing. Check the reply, then the path, then the settings, in that order, and avoid rewriting the whole plan on a guess.

Why the first question matters most

Many testers spend an hour adjusting a path that was never wrong. The server returned an error page, a login screen or an empty body, and the path simply had nothing to read. Looking at the real reply first costs ten seconds and removes the most common false trail. Keep the habit: before touching any setting, open the reply that the extractor actually received and read it with your own eyes.

The second most common cause is timing. The extractor reads the reply of its own request, so it must sit under the request that produces the value, not under a neighbour. When an element is moved or copied in a large plan, its place in the tree changes silently, and it may start reading a reply that does not hold the field. A quick look at the tree structure, and at the name of the request above the extractor, confirms that the right pair is together.

!
Common Mistake

Changing several things at once while debugging. Change one thing, run once, look at the result. If you change three things and the problem disappears, you will not know which change fixed it, and it will return.

30Pre-Flight Checklist and Long-Term Maintenance of Extractors

Extractors depend on the shape of replies, and replies change. A small routine keeps plans healthy.

An extractor is a quiet promise: “the value you need lives at this address.” When the service changes its reply, the promise can break without any visible error in the plan itself. A short check before each important run, and a regular review after each release, keeps the promise honest and protects your results.

AreaQuestion to askWhy it matters
PathsWere all paths tested on a fresh, real reply?Catches changed field names and positions
DefaultsDoes every extractor have an obviously fake default?Makes failures visible
AssertionsIs there an existence check beside each extractor?Failures appear on the right request
LoopsDoes every loop have a safety limit?Prevents runaway traffic
TokensIs expiry handled for the test duration?Avoids late-run authorization errors
CostAre only needed values extracted, with exact paths?Protects generator accuracy
SecurityAre secrets kept out of saved files and screenshots?Prevents leaks
DebugAre debug elements disabled for the real run?Saves memory and avoids exposure
1

Healthy run

One user, one loop. Every extracted variable holds a real value, and every assertion passes.

2

Broken run

Break one path on purpose. The default appears and the matching assertion fails with a clear message.

3

Small concurrent run

A handful of users with different data. Each one should see its own token and its own identifiers.

4

Real run

Start the full test, watch the failure counts by request name, and keep an eye on the generator.

Habits that keep plans healthy

Habit

Review after every release

Compare replies with the previous release. Update paths on purpose after confirming the change was intended.

Habit

Keep sample replies

Store healthy and broken replies next to the plan, so paths can be tested without a live system.

Habit

Remove unused extractors

Delete extractors whose variables nobody uses. They cost time and confuse readers.

Habit

Keep a variable map

One page that shows where each variable is born, used and what happens when it is missing.

!
Common Mistake

Fixing a path after a release without asking whether the change was announced. A renamed field may break real clients too, and your failing test may be the first warning anyone gets.

Keep a small library of known good samples

Teams that test often benefit from a folder of sample replies, one healthy and one broken for each important request. With these files you can try a new path in seconds, show a colleague exactly what the service returned on a bad day, and review changes without touching a live environment. Samples also work as living documentation. A new tester can read them and understand the journey faster than from any written description, because they show real field names, real nesting and real values.

31Version Differences and Compatibility Notes

Small details can differ between versions. Verify on your own installation.

JMeter and its path library evolve. Details such as how a null is stored, how a numeric value is written back, which functions are available inside a path, or which related extractors ship with the tool can differ between versions. This guide describes the general behaviour that holds across common recent versions, and it avoids promising exact details that may change.

What to verify on your version

Check

Null handling

Run a reply with a null value and look at what the variable holds. Decide how your plan treats it.

Check

Number formatting

Extract a large identifier and a decimal, and compare them with the original reply.

Check

Match variables

Confirm which numbered and count variables appear for single, random and all-match settings.

Check

Filter and function support

Try the filter or function you plan to use in the path tester before building the plan around it.

Check

Related elements

See which extractors your version offers, so you know whether a query-language alternative is available.

A one-page compatibility test

Keep a tiny test plan with a few sample replies and the extractors you rely on. Run it whenever you upgrade the tool or move to a new machine. If any variable changes its value or format, you know before your real tests do. This small habit has saved many teams from chasing a “service problem” that was really a tool upgrade.

Simple Analogy

A cook who changes ovens always bakes a test loaf first. The recipe has not changed, but each oven has its own habits. A one-page compatibility test is the test loaf of your plan.

i
Practical Tip

Write the tool version in your test report. When results differ between two runs, the version is the first thing to compare.

32Frequently Asked Questions

Short, plain answers to the questions testers ask most often.

Q1What does the JSON Extractor do?

It reads a reply, follows one or more paths to find values, and stores them in variables that later requests, assertions and controllers can use.

Q2When do I need it?

Whenever a later request depends on something the server created in an earlier reply, such as tokens, identifiers, page markers and status values.

Q3How do I extract several values at once?

Give lists of names, paths and defaults, separated by semicolons and in the same order. The first name pairs with the first path and the first default.

Q4What does Match No. do?

It decides which match to keep when a path finds several: a positive number for that numbered match, zero for a random one, and minus one for all matches with a count variable.

Q5Why does my variable hold the default?

The path found nothing. Most often the reply was not what you expected, such as an error page, or the path has a spelling, case or position mistake. Test the path in the path tester on the real reply.

Q6What should I use as a default value?

A clearly fake value such as NOT_FOUND, never something that looks real like zero or one, and never an empty value.

Q7How do I loop over all extracted items?

Set Match No. to minus one, then use a ForEach Controller with the variable name as the prefix, a start index of zero, an end index equal to the count or a smaller limit, and the underscore option ticked.

Q8Are extracted values numbers or text?

Text. Convert them in a later step when you need arithmetic or numeric comparison.

Q9Can two virtual users share an extracted variable?

Not directly. Variables belong to one user. Shared values can travel through properties, which are visible to all users on the same JMeter process but not across worker machines.

Q10Should I add an assertion next to every extractor?

Yes, whenever a later step depends on the value. An existence check on the same path makes failures appear on the request that caused them.

Q11Does extraction slow down my load test?

A little. Each extraction parses the reply. Use exact paths, extract only what you need, and compare generator load with and without extractors.

Q12How do I handle tokens that expire during a long test?

Log in again each iteration, refresh before the lifetime ends using an extracted expiry, or react to an authorization failure with one new login. Pilot the test for longer than the token lifetime.

33Summary and Key Takeaways

The short version, for the day you only have two minutes.

The JSON Extractor is the bridge between one reply and the next request. It reads a path, stores the result in a variable and lets your journey follow real data instead of fixed guesses. Used with care, it makes tests realistic, repeatable and easy to debug. Used carelessly, it hides failures behind stale or fake values.

Key Takeaways

  • Extract what the server creates — tokens, identifiers, page markers and status values change with every run, so the plan must read them from replies instead of hard-coding them.
  • Learn the fields — names, paths and defaults are paired by position, and Match No. decides between first, random, specific and all matches.
  • Make failure loud — use obviously fake defaults and add an existence assertion beside every extractor, so problems appear on the request that caused them.
  • Prefer exact paths — they are faster, clearer and fail visibly when the structure changes, while searches can quietly pick the wrong field.
  • Loop with limits — ForEach, pagination and polling loops need the count variable or a counter, so a stuck reply cannot trap users for ever.
  • Mind scope and cost — variables belong to one user, properties are shared inside one process, and every extraction costs parsing time on the generator.
  • Protect secrets — keep tokens out of saved results, shared screenshots and messages, use synthetic data, and review plans after every release.