The Once Only Controller in JMeter: Do It One Time, Then Move On
A deep, plain-English guide to the controller that runs its steps only on a virtual user's first pass, covering how it works inside, how it behaves in loops, how it differs from its alternatives, and the traps that quietly distort load test results.
Think about visiting a large office building. At the front desk you show your identity card and receive a visitor badge. After that you spend the whole day walking between meeting rooms, and nobody asks you to return to the desk and prove who you are before every single door. The badge check happens once, at the start of your visit, and everything after it relies on the badge you already hold.
A realistic performance test should behave in the same sensible way. A virtual shopper signs in once and then browses, searches and buys many times. If your test makes every virtual user sign in again at every loop, you are measuring a world that does not exist. JMeter offers a small, humble element for exactly this situation, called the Once Only Controller. This guide explains it from zero knowledge, shows how it works inside, and teaches you where it helps, where it misleads and what to use instead.
1What the Once Only Controller Is and Why It Exists
We begin with the problem it solves, because the tool only makes sense once the problem is clear.
The repetition problem
A JMeter virtual user, called a thread, normally walks through its steps from top to bottom and then, if the test says so, walks through them again. Each walk is called an iteration. This repetition is what generates sustained load. The trouble is that some steps in a real journey are not repeated by real people. Signing in, accepting terms and conditions, downloading a configuration file or opening a long-lived connection usually happen once per visit, not once per action.
The solution in one sentence
The Once Only Controller is a container. Whatever steps you place inside it are executed during each thread’s first iteration only, and are skipped on every later iteration. The thread then continues with the rest of its journey as normal.
What happens without it
Without a way to run steps once, test authors tend to fall into one of two poor habits. Some put the sign-in at the top of the repeated section, so every iteration signs in again and the authentication system receives many times its real traffic. Others try to avoid sign-in altogether by pasting a fixed token into every request, which means the test never exercises real sessions and every virtual user pretends to be the same person. Both habits produce numbers that look precise and mean very little. The Once Only Controller gives a third, far more honest option.
Why it matters for accuracy
If sign-in were repeated in every iteration, the authentication system would receive far more traffic than in real life, and the rest of the journey would receive less, because time is wasted signing in again. The numbers would blame the login service for slowness that real users never see, while hiding how the actual pages behave. A single small controller removes this distortion.
Think of a theatre. You buy a ticket once at the box office and then watch many scenes. The Once Only Controller is the box office: every audience member passes through it once, at the start, and the play that follows never asks for the ticket again.
2Core Concepts You Need First
A few terms appear throughout this guide, and learning them now makes everything easier.
Thread
One virtual user. Ten threads means ten simulated people acting at the same time, each with their own private state.
Iteration
One complete walk through the steps a thread has been told to repeat. A thread set to loop twenty times performs twenty iterations.
Logic Controller
An element that decides which of its children run, in what order and how often. It does not send requests itself.
Sampler
The element that actually sends a request and records the outcome, such as a web call or a database query.
Thread Group
The element that defines how many virtual users run, how fast they start and how many times they repeat.
Variable
A named value that belongs to one thread, such as a token that user received. Other threads cannot see it.
Property
A named setting shared by every thread in the test. This difference between private variables and shared properties becomes important later.
Session
The conversation between a user and an application after sign-in, usually tracked by a cookie or a token.
The Once Only Controller counts per thread. It never means “once for the whole test”. That single distinction prevents the most common mistakes covered later in this guide.
3Where It Fits Among Logic Controllers
The Once Only Controller is one member of a family, and seeing its relatives clarifies its purpose.
| Controller | What It Decides | Typical Use |
|---|---|---|
| Simple Controller | Nothing; it only groups children | Organising a plan |
| Loop Controller | Repeat children a set number of times | Repeating an action |
| Once Only Controller | Run children on the first pass only | Login and one-time setup |
| If Controller | Run children only if a condition is true | Conditional steps |
| While Controller | Repeat children while a condition holds | Polling until ready |
| Interleave Controller | Run one child per pass, rotating | Alternating actions |
| Random Controller | Run one randomly chosen child | Varied behaviour |
| Throughput Controller | Run children a percentage or number of times | Traffic mix control |
| Transaction Controller | Group children into one timed unit | Business-level timing |
flowchart TD
T[Thread Group] --> O[Once Only Controller]
T --> L[Loop of repeated actions]
O --> A[Login request]
O --> B[Fetch settings request]
L --> C[Browse products]
L --> D[Search]
L --> E[Add to basket]
The Once Only Controller sits beside the repeated work, not around it. Its children run in the first iteration, and the thread then carries on with everything else in the group.
4How It Works Inside
The behaviour looks like magic until you see the simple bookkeeping behind it.
Each thread carries its own tree
When a test starts, every thread receives its own private copy of the parts of the plan it will run, along with its own state. This is why one user’s variables are invisible to another. The Once Only Controller lives inside that private copy, so its memory of whether it has already run belongs to that one thread. Thread number seven having completed its sign-in says nothing about thread number eight.
The first-iteration rule
When the thread reaches the controller, it asks one question: is this the first iteration of my enclosing loop? If yes, the controller passes the thread into its children, which then run in the order they appear. If no, the controller steps aside and the thread moves directly to the next element. No request is sent, no time is recorded and nothing appears in the results for that skipped pass.
The controller itself produces no sample
A logic controller is not a sampler. The Once Only Controller adds no timing of its own. What you see in the results are only the samples of the children that actually ran. If you want one combined timing for the whole sign-in sequence, wrap the children in a Transaction Controller inside it.
sequenceDiagram
participant U as Virtual User
participant O as Once Only Controller
participant S as Login Sampler
participant J as Journey Samplers
U->>O: Iteration 1 arrives
O->>S: Run children
S-->>U: Login result and token
U->>J: Browse and search
U->>O: Iteration 2 arrives
O-->>U: Skip children
U->>J: Browse and search again
U->>O: Iteration 3 arrives
O-->>U: Skip children
U->>J: Browse and search again
Imagine a security guard with a clipboard, one clipboard per visitor. The first time a visitor arrives, the guard performs the ID check and ticks the box. On every later arrival the guard sees the tick and waves the visitor through. Each visitor has a separate clipboard, so one visitor’s tick never excuses another.
Believing the controller keeps a single global flag for the entire test. It does not. If a hundred threads run the plan, the children run a hundred times in total, once for each thread.
5The Loop Rule: Behaviour Under a Parent Loop
The controller is often misunderstood when it sits inside another looping controller, so this chapter takes it slowly.
The rule as documented
The official description says that the Once Only Controller runs during the first iteration of whatever looping parent surrounds it. When it sits directly under a thread group, that means the first iteration of the thread’s own loop, which is the familiar once-per-user behaviour. When it sits inside a Loop Controller, the first iteration of that loop is meant, and this happens again every time the outer thread loop brings the thread back into that Loop Controller.
A worked example in words
Suppose a thread group makes each user repeat three times. Inside it sits a Loop Controller set to loop five times, and inside that Loop Controller sits a Once Only Controller followed by a search sampler. On the thread’s first outer pass, the Loop Controller begins, and on its first inner iteration the Once Only children run once. Inner iterations two to five skip them. On the thread’s second outer pass, the Loop Controller starts afresh, so its first inner iteration again runs the Once Only children. By the end, the children have run three times, once per outer pass, not once in total.
Outer pass 1, inner loop 1
The once-only children run, then the search runs.
Outer pass 1, inner loops 2 to 5
The once-only children are skipped; only the search runs each time.
Outer pass 2, inner loop 1
The inner Loop Controller starts fresh, so the once-only children run again.
Outer pass 2, inner loops 2 to 5
Skipped again, with only the search running.
Placing the controller inside a Loop Controller and expecting a single execution per user. If you truly need once per user, place it directly in the thread group, outside any inner loop.
6A Walkthrough: Sign In Once, Then Browse
The classic use case, built step by step, makes the idea concrete.
The scenario
An online store wants to know how its catalogue pages behave when two hundred shoppers browse at the same time. Each shopper signs in, then repeatedly opens a category page, a product page and a search result. The goal is to measure the browsing pages, not the sign-in.
Create the thread group
Set two hundred users, a sensible ramp-up and either a fixed loop count or a duration. Leave the option that keeps the same user across iterations switched on.
Add the Once Only Controller first
Place it directly under the thread group, above the repeated browsing steps.
Put the sign-in inside it
Add the sign-in request, and an extractor if the response contains a token that later requests need.
Add the browsing steps after it
Category page, product page and search follow, outside the controller, so they repeat every iteration.
Add shared helpers
A cookie manager or a header manager at thread-group level supplies the session to every request.
Prove it with one user
Run a single user for several iterations with a results viewer and confirm the sign-in appears only in the first iteration.
When sign-in has several steps
Real sign-in is rarely one request. A user may load the sign-in page, receive a security token embedded in it, submit credentials, and then be redirected to a landing page that sets further cookies. All of these steps belong together inside the controller, in their true order, so that the session is complete before the browsing begins. If only the final credential submission is inside the controller and the earlier page load is outside it, the page load will repeat on every iteration, wasting traffic and confusing your counts.
flowchart LR
A[Thread starts] --> B{First iteration?}
B -- Yes --> C[Run sign-in once]
B -- No --> D[Skip sign-in]
C --> E[Browse category]
D --> E
E --> F[Open product]
F --> G[Search]
G --> H{More iterations?}
H -- Yes --> B
H -- No --> I[Thread ends]
The sign-in request will appear exactly as many times in your results as there are threads. That number is a useful self-check: if you see far more sign-ins than users, something is wrong with placement.
7Per-Thread Versus Per-Test: The Biggest Confusion
Many people reach for this controller when what they really need is something that runs once for the entire test.
Two very different needs
Some work must happen once per virtual user, such as that user’s own sign-in. Other work must happen once for the whole test, such as creating a shared set of products, preparing a database, or fetching one administrator token that every thread reuses. The Once Only Controller serves the first need only. If you place a data creation step in it, and you run five hundred threads, the step runs five hundred times, which may be exactly the problem you were trying to avoid.
| Need | Right Tool | Why |
|---|---|---|
| Each user signs in once | Once Only Controller | Runs once per thread |
| Prepare shared data before the test | setUp Thread Group | Runs before the main thread groups, a single time |
| Clean up after the whole test | tearDown Thread Group | Runs after the main thread groups finish |
| Run something a fixed number of times across all users | Throughput Controller in total-executions mode | Counts executions across the test |
| Run a step only for the first user | If Controller with a thread-number condition | Uses the thread’s own number as the test |
A hotel has two kinds of one-time jobs. Each guest checks in once, which is like the Once Only Controller. But the hotel is built once for all guests, which is like a setup thread group. Mixing them up would mean rebuilding the hotel for every arriving guest.
Putting an administrator action such as “create test catalogue” inside the Once Only Controller. With many users, you will create many catalogues, pollute the system under test, and invalidate the run.
8Variables, Cookies and Session State
Running sign-in once only helps if the result of that sign-in survives to later iterations, and that is not automatic.
Variables persist per thread
A value extracted during the first iteration, such as a token or a user identifier, is stored in a variable that belongs to that thread. In normal circumstances it remains available in every later iteration, because variables are not cleared between iterations. This is what allows the browsing steps to use a token obtained once at the start.
It helps to remember the difference between a variable and a property here. A variable belongs to one thread and is the correct home for personal values such as a token. A property is shared by the whole test, so storing a personal token there would make every user overwrite everyone else’s. If you ever need to hand a value from a setup group to the main users, a property is the right bridge, but a token that identifies one user must stay in that user’s own variable.
Cookies and the same-user setting
Web sessions often live in cookies. Two settings can silently erase them. The thread group has an option, usually described as using the same user on each iteration, which is normally switched on. When it is switched off, JMeter treats each iteration as a brand new browser: cookies, caches and connections are reset. The cookie manager also has its own option to clear cookies at the start of every iteration. If either is active, the session created in the first iteration vanishes, and from the second iteration the user is effectively signed out, but the sign-in never runs again.
Same User Each Iteration
Keep it enabled when using the Once Only Controller for login, so the session survives.
Cookie Manager Clearing
Make sure the option to clear cookies each iteration is switched off for sign-in-once designs.
Cache Manager Clearing
Decide deliberately whether the browser cache should persist; it affects how many requests reach the server.
Token Variables
Confirm tokens are stored in thread variables and that no later step overwrites them accidentally.
Everything works in iteration one and then every later request returns an authorisation error or a redirect to the sign-in page. This pattern almost always means session state was cleared between iterations.
9The Alternatives and When Each Wins
The Once Only Controller is one tool among several, and each alternative solves a slightly different problem.
setUp Thread Group
A special thread group that runs before every regular thread group and finishes before they start. It is the right place for one-time preparation of the environment, such as creating shared accounts or fetching a single shared credential. Values it produces can be shared with other thread groups through properties, because ordinary variables are private to a thread.
tearDown Thread Group
The mirror image, running after the regular groups end. It is the correct place for cleanup, such as deleting test data, because the Once Only Controller can only act on the first iteration, never the last.
Throughput Controller in total-executions mode
Runs its children a chosen number of times across all threads together. With a count of one and the per-user option off, the children run exactly once in the whole test, no matter how many threads exist. A per-user option changes the counting to each thread separately.
If Controller with a condition
Runs its children only when a condition is true. By testing something such as whether a token variable is already filled, it can sign a user in only when needed, which also lets a user sign in again after the token expires.
Separate thread group for sign-in tests
If the goal is to measure the sign-in service itself, a dedicated thread group where sign-in is the repeated action gives far better statistics than a once-only step that runs only at the start.
Include or Module Controller
These reuse a block of steps in several places. Combined with the Once Only Controller they keep a plan tidy when the same one-time sequence is needed in more than one scenario.
Ask who the “once” belongs to. If it belongs to each user, use the Once Only Controller. If it belongs to the whole test, use setUp or a total-executions Throughput Controller.
10Choosing the Right Approach
A decision table turns the options into a confident choice.
| Your Situation | Choose | Reason |
|---|---|---|
| Every user must sign in once and keep a session | Once Only Controller | Simple, readable and per-user |
| All users share one administrator token | setUp Thread Group | One fetch, shared through a property |
| Session tokens expire during a long test | If Controller with a freshness check | Allows repeated sign-in when needed |
| You want to measure sign-in capacity | Dedicated login thread group | Many samples give reliable statistics |
| Something must run exactly once in the whole test | Throughput Controller, total executions | Counts across threads |
| Cleanup after the test | tearDown Thread Group | Runs once after all load ends |
| Each iteration should be a brand new visitor | No controller; disable same-user setting | Resets cookies and caches each pass |
Three questions to ask
First, who owns the repeated action in real life, the user or the system? Second, how long will the test run compared with how long a session or token stays valid? Third, what is the purpose of the test: to measure the repeated journey, or to measure the one-time step? Answering these three questions usually reveals the right element within a minute.
11What It Does to Your Reports and Statistics
Because the controller skips work, the numbers in your report look different, and that difference needs interpreting.
Sample counts reflect execution
Every sampler inside the controller produces one sample per execution. With two hundred threads, you will see about two hundred sign-in samples, while the browsing requests may number in the tens of thousands. This is correct and expected, but it affects how much you can trust each row of the statistics table.
Percentiles need enough samples
A ninety-fifth percentile computed from two hundred samples is far less stable than one computed from fifty thousand. A single slow sign-in changes the figure noticeably. When the sign-in row of your report looks alarming, check the number of samples before panicking, and rerun if necessary.
Throughput is not constant
Sign-in requests happen only when users arrive, so their rate depends on the ramp-up and then drops to zero. The rate of sign-ins over time therefore looks like a bump at the start of the test, not a steady line. This is the realistic shape for a one-time action, but it surprises people who expected a flat chart.
Label one-time steps clearly, for example with a prefix, so readers of the report immediately understand why their sample count is small and do not compare them unfairly with repeated steps.
Quoting the sign-in average from a once-only test as if it were the sign-in service’s steady-state capacity. It only reflects the arrival burst of the ramp-up, a very different question.
12Ramp-Up and the Shape of Once-Only Load
The rate at which users start decides how hard the one-time steps hit the system.
Arrival rate equals users divided by ramp-up
If two hundred users start over one hundred seconds, about two new users begin every second, and each new user triggers one sign-in. The authentication service therefore sees roughly two sign-ins per second during the ramp, and nothing afterwards. If you shorten the ramp to ten seconds, the same two hundred sign-ins arrive at about twenty per second, a tenfold increase in pressure on that one service.
Why this matters
Real systems often face sign-in storms at particular moments, such as the start of a working day or a sale. A test that ramps users slowly will never reveal weakness in sign-in. A test that ramps users abruptly may overstate the problem if real arrivals are gentler. Choose the ramp-up to match the arrival pattern you want to study, and state it in your test notes.
Estimating the sign-in load before you run
You can predict the pressure on the authentication service with simple arithmetic. Divide the number of threads by the ramp-up time in seconds to get the arrival rate, then compare it with the rate the service handles in production at its busiest moment. If your plan produces ten times the real peak, you are running a stress test of sign-in, not a realistic test of browsing, and you should say so in your notes. If it produces a tenth of the real peak, you will learn nothing about sign-in capacity. Doing this sum takes a minute and prevents many arguments after the results arrive.
flowchart LR
A[Short ramp-up] --> B[High sign-in rate at the start]
B --> C[Stress on authentication service]
D[Long ramp-up] --> E[Gentle sign-in rate]
E --> F[Browsing load dominates]
C --> G[Different bottlenecks found]
F --> G
Imagine a concert venue with a ticket check at the door. If the crowd arrives over three hours, the door staff cope easily. If everyone arrives in ten minutes, a queue forms at the door even though the concert hall itself is perfectly fine. The ramp-up decides which situation your test creates.
Run two versions of the test: one with a realistic ramp-up for browsing behaviour, and one with a deliberately aggressive ramp-up to stress the sign-in. Compare the results rather than trusting a single arrangement.
13Token and Session Expiry in Long Tests
A sign-in that happens only once can outlive the session it created, and the test then quietly turns into a test of error pages.
The hidden clock
Most applications give sessions and tokens a lifetime, often measured in minutes. A test that runs for an hour with a token valid for twenty minutes will see healthy results for the first twenty minutes and then a flood of authorisation failures. Because the sign-in was a once-only step, nothing in the plan ever refreshes the token.
Ways to handle it
Know the lifetime
Ask the application team how long a session or token stays valid and whether activity extends it.
Compare with the test length
If the test is shorter than the lifetime, once-only sign-in is perfectly safe.
Add a refresh path
For longer tests, store the time of sign-in in a variable and use a conditional controller to sign in again when the token is close to expiry.
Or use a refresh endpoint
If the application provides a refresh operation, call it periodically in the repeated part of the journey.
Assert on authorisation
Add assertions or error checks that clearly flag expired sessions so they cannot hide inside an average.
Problem
A two-hour soak test signs users in once and then repeats the journey for the entire duration.
Why It’s Harmful
After the token expires, most requests fail or are redirected. The report shows a rising error rate that is blamed on the application, when the real cause is the test design.
Correct Approach
Match the sign-in strategy to the session lifetime, either by refreshing tokens or by repeating sign-in at the real interval users would experience.
14Test Data and Data-File Interactions
Data files and one-time steps can interfere with each other in surprising ways.
The credentials file
Tests commonly read usernames and passwords from a file, giving each thread its own row. The data-file element reads a new row as threads iterate. If it advances every iteration while the sign-in runs only in the first, the user-name variable on later iterations will belong to a different person than the one who actually signed in. Later requests that quote the username, such as a profile page or an order history, may then ask for someone else’s data.
Ways to stay consistent
Copy at Sign-In
Right after sign-in, store the username in a differently named variable that is not touched by the data file again.
Control File Scope
Place the data-file element so it is read only where needed, and check its sharing mode against your intention.
Avoid Reusing Quoted Values
Prefer identifiers from the sign-in response to values read from the file when later requests need user context.
Size the File Properly
Provide at least one row per thread, and decide what happens when the file ends, so users do not share accounts unintentionally.
Two threads signing in with the same account at the same time. Many applications limit simultaneous sessions per account, so the second sign-in may log out the first, producing errors that have nothing to do with performance.
Add a small check that confirms the signed-in identity on a later iteration, for example by asserting that a profile page shows the expected name. It quickly catches mixed-up data.
15Timers, Assertions and Extractors Around the Controller
Supporting elements follow scope rules, and the Once Only Controller changes what falls inside that scope.
Scope decides who is affected
Timers, assertions and extractors apply to the samplers in their scope, which means the samplers at or below their position in the tree. A timer placed inside the Once Only Controller delays only the one-time steps. A timer placed at thread-group level delays every sampler, including those inside the controller. Decide on purpose where each helper belongs.
Think time for the first iteration
Real people pause after signing in, often to look at the landing page. A short think time after the one-time steps makes the first iteration resemble real behaviour. Without it, many users hit their first browsing request in the same instant they finish signing in.
Extractors must be reliable
If the extractor that captures the token fails during the one-time sign-in, nothing will retry it. Every later iteration will then use an empty or stale value. Always add an assertion directly on the sign-in request and consider stopping the thread if sign-in fails, since continuing would only create a stream of meaningless errors.
Failure handling for the sign-in
Set the thread group’s behaviour after a sampler error to stop that thread. A user who could not sign in has nothing useful to do, and letting it continue pollutes your results.
Assertions that prove the session
Check that the sign-in response contains the expected marker, not merely a success code. Some systems return a success code together with an error message in the body.
Timer placement
Use one timer inside the controller for post-sign-in pauses and a separate timer in the repeated section for normal think time, so each represents a different human behaviour.
16Placement and Nesting Rules
Where you put the controller matters as much as what you put inside it.
Directly under the thread group
The most common and most predictable placement. The children run in each user’s first iteration of the thread loop. Put it above the repeated steps so the one-time work happens first.
Inside a Loop Controller
The children run on the first inner iteration each time the loop starts, which may be many times per user, as described earlier. Useful when each cycle of an outer loop is a separate session, but rarely what a beginner wants.
Inside a Transaction Controller
A Transaction Controller around the Once Only Controller records a combined time for the one-time sequence, but only on iterations where something actually ran. On skipped iterations the transaction may show nothing meaningful, so check how your report treats it.
Inside an If Controller
Allowed, and sometimes useful, but conditions evaluated on later iterations may never be reached by the once-only logic, making the behaviour confusing to read. Prefer clearer designs.
Inside a Random or Interleave Controller
Legal but unpredictable. A rotating or random choice may not select the once-only branch on the first iteration at all, so the one-time step might never run. Avoid unless you understand the rotation exactly.
Inside reusable fragments
When a one-time block is placed in a reusable fragment and included from several places, each inclusion counts independently according to the parent loop where it sits. Test each inclusion separately.
When in doubt, place the controller directly under the thread group and keep it away from clever combinations. The easiest plan to read is also the easiest to trust.
17Behaviour in Distributed Tests
When several machines generate load together, the word “once” still means once per thread, and the numbers multiply.
Each worker runs the whole plan
In a distributed test, the controller machine sends the full plan to every worker, and each worker runs its own set of threads. Thread counts therefore apply per worker. The Once Only Controller operates inside each thread, exactly as before, so the total number of one-time executions equals the total number of threads across all workers.
What this means for shared steps
If you place a “create shared data” step in a Once Only Controller and run three workers with a hundred threads each, that step runs three hundred times. For one-time work that belongs to the whole test, use the setUp thread group, remembering that in distributed mode it also runs on each worker, so shared preparation should be idempotent or done outside JMeter.
flowchart LR
C[Controller] --> W1[Worker 1: 100 threads]
C --> W2[Worker 2: 100 threads]
C --> W3[Worker 3: 100 threads]
W1 --> S1[100 sign-ins]
W2 --> S2[100 sign-ins]
W3 --> S3[100 sign-ins]
S1 --> A[Authentication service sees 300 sign-ins]
S2 --> A
S3 --> A
Forgetting that the sign-in data file must exist on every worker with enough distinct accounts. If each worker reads the same first rows, three workers will sign in with the same accounts at once.
Split the credentials into separate files per worker, or provide a worker-specific property that selects a different range of accounts for each machine.
18Debugging the Controller
Because the controller hides work, bugs show up as things that did not happen, which are harder to notice.
Run one user for several iterations
Use at least three iterations so you can see the difference between the first and later passes.
Open a detailed results viewer
Confirm the sign-in appears once, at the very beginning, and never again.
Inspect variables after each iteration
A debug element placed in the repeated section shows whether the token and user variables are still filled.
Check request headers on later iterations
Verify that the token or cookie is actually being sent in iteration three, not just in iteration one.
Try two users
Confirm each user has their own token and that their data does not mix.
Count the sign-ins in a larger run
The total should equal the thread count. Any other number means the controller is placed or configured differently from what you intended.
If sign-ins are too many, the controller is probably inside a loop. If later requests fail with authorisation errors, session state was probably cleared or the token expired. If sign-ins are missing for some users, the controller may sit under a branching element that did not select it.
19GUI Mode Versus Command-Line Mode
The controller behaves identically in both modes, but your way of working should differ.
Same logic, different purpose
The skipping logic lives inside the engine, so the plan behaves the same whether it is run from the graphical interface or from the command line. Use the graphical interface to build the structure and to prove with one or a few users that the sign-in runs once. Use the command line for real load with a lightweight results writer.
Parameterise what changes
Expose the number of threads, the ramp-up time, the number of iterations and the credentials file location as properties with default values. That lets the same plan run as a one-user proof in the graphical interface and as a large run from the command line without edits.
Remember the heavy listeners
The detailed results viewer you used to verify the once-only behaviour should be disabled before a heavy run, because it stores every request and response in memory and distorts timings at scale.
| Activity | Best Mode | Reason |
|---|---|---|
| Placing the controller and children | GUI | Visual tree makes structure obvious |
| Proving sign-in runs only once | GUI with one user | Detailed viewer shows every request |
| Running two hundred users for an hour | Command line | Lower overhead and repeatable |
| Counting sign-ins afterwards | Report or results file | Sample counts confirm placement |
20Watching the System Under Test
A controller that changes your traffic pattern also changes what the application experiences, so watch the right metrics.
Authentication service
Expect a burst of load during the ramp-up and quiet afterwards. Watch sign-in rate, response time, token issuance and any rate limiting, especially if the ramp-up is short.
Session storage
Because users keep their sessions for the whole test, the number of live sessions grows to the thread count and stays there. Watch session store memory and size, and expiry behaviour.
Application servers
Steady-state load matches the repeated journey only. Compare processor, memory and connection usage after the ramp-up, when the behaviour is stable.
Database
Sign-in often touches user tables and writes audit records. Expect a short burst of such activity early on, followed by the pattern produced by browsing.
Caches
Each session may populate per-user caches once. The first browsing iteration may therefore be slower than later ones, which is real behaviour worth noticing.
Mark the end of the ramp-up on your monitoring dashboards. Conclusions about steady-state performance should be drawn from the period after that marker, when every user has signed in.
21Security Considerations
A step that handles credentials and tokens deserves the same care as any other sensitive part of a test.
Keep credentials out of the plan
Sign-in details belong in a protected data file or in secure run-time properties, never typed into the plan itself, where they would be saved in version control and visible to anyone who opens it.
Use dedicated test accounts
Create accounts used only for testing, with limited permissions. Never run a load test with real customer or employee accounts, and never with an all-powerful administrator account.
Protect tokens in results
Saved request headers, cookies and response bodies may contain live tokens. Store results files securely, restrict who can read them and delete them according to policy.
Expect protective systems to react
A burst of sign-ins during a short ramp-up can trigger rate limiting, bot detection or account lockout. Tell the security team beforehand and agree the window so the test is not mistaken for an attack.
Avoid testing against production by default
Signing in many synthetic users on a live system can send real notifications, write audit logs and affect real users. Prefer an isolated environment unless a production test is formally approved.
Sharing a results file in a public chat or ticket without checking whether it contains tokens or personal data. A token in a pasted line can be used by anyone until it expires.
22Design Patterns That Work
These patterns appear again and again in tidy, trustworthy plans that use one-time steps.
Login Once, Browse Many
Sign-in inside the controller at the top, repeated journey below. The simplest and most common arrangement.
Copy Identity After Sign-In
Store the signed-in user’s identity in a fresh variable so later data-file reads cannot overwrite it.
Guarded Refresh
Combine the one-time sign-in with a conditional refresh for long tests, so tokens are renewed only when needed.
Setup for Shared, Once Only for Personal
Use the setUp thread group for test-wide preparation and the Once Only Controller for each user’s own start-up.
Fail Fast on Sign-In Errors
Stop a thread whose sign-in failed rather than letting it flood the results with consequent errors.
Labelled One-Time Steps
Name one-time samplers clearly so report readers immediately see why their counts are small.
Naming and documentation habits
Give the controller a descriptive name, such as one that says it holds each user’s start-up work, and add a short comment explaining the assumptions: how long the token lives, which setting keeps the session, and where the credentials come from. A plan that is read months later by a colleague, or by you, is far easier to trust when the reasons behind its structure are written next to the elements they explain.
A well-run event has a registration desk for each guest and a one-time venue setup for everyone. Keeping those two jobs separate means nobody sets up the whole venue each time a guest arrives.
23Anti-Patterns to Avoid
These mistakes look harmless, and each one quietly spoils results.
Problem
Shared preparation, such as creating a catalogue of test products, is placed inside the Once Only Controller.
Why It’s Harmful
The step runs once per thread, creating hundreds of duplicates, slowing the system and altering the data that later requests rely on.
Correct Approach
Use the setUp thread group for test-wide preparation, and keep the Once Only Controller for each user’s personal start-up only.
Problem
The sign-in once-only design is combined with a setting that clears cookies or resets the user at each iteration.
Why It’s Harmful
Users are effectively signed out after the first iteration, but nothing signs them in again, producing a long run of authorisation failures.
Correct Approach
Keep the same-user option enabled and switch off cookie clearing, or abandon once-only sign-in and sign in on every iteration deliberately.
Problem
The sign-in service’s performance is judged from a once-only sign-in in a browsing test.
Why It’s Harmful
Few samples, a burst shaped by the ramp-up and no sustained load make the numbers unreliable as a measure of capacity.
Correct Approach
Create a dedicated scenario that repeats sign-in at the target rate and measure the service on its own.
Problem
The controller is nested inside random or rotating controllers, or deep inside reusable fragments, with no clear test of its behaviour.
Why It’s Harmful
The one-time step may never run for some users, or may run more often than expected, and nobody notices because skipped steps leave no trace.
Correct Approach
Place it simply under the thread group and verify the sign-in count equals the thread count after every structural change.
Problem
Cleanup steps such as logging out or deleting created data are put inside the Once Only Controller at the end of the plan.
Why It’s Harmful
The controller runs only in the first iteration, so cleanup happens at the very beginning, wiping out the session or data the rest of the journey needs.
Correct Approach
Use the tearDown thread group for test-wide cleanup, and design per-user logout as part of the final iteration through explicit conditions.
24Advantages, Disadvantages and Trade-offs
An honest look at benefits and costs helps you decide when the controller is the right answer.
Advantages
- Very simple to add and easy to read in the plan tree
- Makes traffic proportions closer to real sessions
- Removes the distortion of repeated sign-in from browsing results
- Reduces unnecessary load on authentication services
- Needs no scripting and no extra plugins
- Works identically in graphical and command-line modes
Disadvantages / Trade-offs
- Counts per thread, which people often mistake for per test
- Behaviour inside loops can surprise newcomers
- Skipped steps leave no trace, making bugs hard to notice
- Cannot refresh expired tokens by itself
- Gives few samples for one-time steps, weakening their statistics
- Cannot run a step on the last iteration
The controller is excellent for one simple job and poor at anything cleverer. When your design needs conditions, refresh or test-wide sharing, move to the more suitable element rather than stretching this one.
25Best Practices Checklist
A short order of operations avoids the stumbles described in this guide.
Decide whose once it is
Per user means this controller; per test means setUp or a total-executions controller.
Place it simply
Directly under the thread group, above the repeated steps, unless you have a clear reason otherwise.
Protect the session
Keep the same-user setting on, turn off cookie clearing and store tokens in thread variables.
Check the clock
Compare the test length with token or session lifetime and add a refresh path if needed.
Guard the sign-in
Assert on its result and stop threads that fail to sign in.
Prove, then scale
Run one user for several iterations, confirm the sign-in count equals the thread count in a larger run, then raise the load from the command line.
Keep a written test note
For every run, record the thread count, ramp-up time, iteration count or duration, the token lifetime, the credentials source and the number of sign-ins observed. These few lines let anyone reproduce the run and quickly explain odd results later. When two runs disagree, the difference very often hides in one of these settings rather than in the application itself.
Trusting that “it worked in iteration one” means it works. Always inspect at least the third iteration, where every one-time assumption is finally tested.
26Uses Beyond Web Sign-In
The controller works with any sampler, so its usefulness extends well past web pages.
Database connections and session setup
A user-specific preparation statement, such as setting a session option, can run once per thread before the repeated queries begin.
Messaging subscriptions
A consumer subscribes to a topic once and then receives many messages. The subscription step belongs in the once-only part, while receiving belongs in the repeated part.
Raw socket handshakes
Many custom protocols require a greeting or login exchange when a connection opens. That exchange runs once per user, then messages flow repeatedly over the same connection.
Configuration downloads
A mobile or single-page application fetches a configuration file at start-up. Reproducing this once per user matches the real client without inflating the request count.
Terms acceptance and onboarding
First-time screens such as accepting terms or choosing preferences happen once per account in real life, and the controller models that faithfully.
For protocols that keep a connection per user, make sure the connection is reused across iterations. Otherwise the repeated part will reopen connections and the once-only handshake will be skipped when it is actually needed.
27Real-World Scenarios
Stories show how the controller helps, and how it can mislead, in everyday projects.
Seasonal sale preparation
An online retailer prepares for a big sale. Each simulated shopper signs in once through the controller and then browses and buys repeatedly. The team separately runs an aggressive-ramp scenario to examine the sign-in storm at the start of the sale.
Banking dashboard soak test
A bank wants to confirm that its dashboard stays stable for eight hours. The first design used only once-only sign-in, and after thirty minutes most requests failed because sessions expired. The team added a conditional refresh and the soak test then ran cleanly.
Distributed test with shared accounts
A team ran three workers and saw strange authorisation errors. All workers were reading the same first rows of the credentials file, so three threads shared each account. Giving each worker its own account range fixed it.
The missing logout
A tester placed a logout step at the end of the plan inside the controller, believing it would run last. It ran first, killing every session, and the whole run produced errors. Moving cleanup to the tearDown group solved the problem.
Cookie clearing surprise
After switching on a cookie manager option that clears cookies each iteration, a previously healthy test began to fail from the second iteration onward. Turning the option off restored the session between iterations.
Mobile app start-up
A mobile backend team modelled each device’s start-up as a once-only block that downloads configuration and registers the device, followed by repeated data synchronisation. Traffic proportions finally matched their production logs.
28Frequently Asked Questions
Once per user, meaning once per thread in its first iteration. With two hundred threads, the children run two hundred times in total.
The controller is most likely inside a Loop Controller or similar element, so it runs on the first iteration of each cycle of that loop. Move it directly under the thread group.
Usually the session was cleared. Check the same-user option in the thread group and any cookie-clearing option, and confirm the token variable is still filled in later iterations.
Not reliably. Use the setUp thread group for preparation, or a Throughput Controller in total-executions mode for work that must be counted across all threads.
No. It only acts on the first iteration. For cleanup, use the tearDown thread group or build explicit conditions for the final iteration.
No. Controllers do not produce samples. You will see rows only for the samplers inside it, unless you wrap them in a Transaction Controller.
The controller will not retry it, because it only runs in the first iteration. Add assertions and make the thread stop on error, otherwise every later iteration will fail in confusing ways.
Not with this controller alone. Combine a conditional controller with a record of the sign-in time, or use a refresh call, so the plan renews the token when it nears expiry.
Each worker runs its own threads, and each thread runs the one-time steps once. The total number of executions equals the total thread count across all workers.
No. Few samples and a burst shaped by the ramp-up make it a poor basis for capacity conclusions. Build a dedicated scenario that repeats sign-in at the desired rate.
It is often a good choice then, because the token stays valid for the whole test. Just confirm the lifetime against the planned duration.
The credentials file has too few rows, wraps around, or is identical on several workers. Provide at least one distinct account per thread across the whole test.
You can, but the behaviour becomes harder to reason about. Prefer placing it directly under the thread group and using separate conditional logic elsewhere.
Run a short test and compare the number of sign-in samples with the number of threads. If they match, placement is correct. If not, inspect the parent elements.
29Summary and Key Takeaways
The Once Only Controller is a small element with a clear job: run its children in each virtual user’s first iteration and skip them afterwards. Used in the right place, it turns an unrealistic test that signs in again and again into a faithful model of a real session. Used carelessly, it hides failed sign-ins, outlives expiring tokens, multiplies shared work across threads and leaves misleading statistics behind. The remedy is to be clear about whose “once” you mean, to keep the design simple, to protect session state, to prove the behaviour with a few iterations, and to reach for setUp groups, conditional controllers or dedicated scenarios when the problem is bigger than a single start-up step.
Key Takeaways
- Once per thread — the controller runs its children in each user’s first iteration; it never means once for the whole test.
- Mind the parent loop — inside a Loop Controller it runs on the first pass of every cycle, so place it directly under the thread group for true once-per-user behaviour.
- Protect the session — keep the same-user setting on, switch off cookie clearing and store tokens in thread variables so later iterations still work.
- Watch expiry — match the sign-in strategy to token lifetime and add a refresh path for long tests.
- Use the right alternative — setUp and tearDown groups for test-wide work, Throughput Controller for counted executions, conditional controllers for refresh.
- Read statistics carefully — one-time steps have few samples and burst-shaped timing, so do not treat them as steady-state capacity.
- Verify and stay safe — count sign-ins against threads, test at least three iterations, and keep credentials and tokens out of plans and shared results.