Skip to content


There are two types of JSR223:

  • Actions: can be dropped anywhere,
  • Pre/Post processors: can be dropped under HTTP Request Actions. These are like JSR223 actions but executed right before or after the enclosing HTTP action.

If you're looking for examples, make sure to also check our samples page.


As OctoPerf is a GUI driven tool, you might encounter some limitation. The JSR223 component opens a new world of possibilities by giving you control of everything through a script:

  • Concatenate values
  • Find the next working day
  • Manipulate variables


JSR223 Action

Parameter name Description Required
Name Descriptive name for this script. No
Language All languages supported by JMeter out of the box are also currently supported by OctoPerf. Yes
Parameters Values to be passed to the script, space separated. Automatically split into an array of strings namedargs[] No
Script The script executed each time the Virtual User comes to this action. Yes
File If provided, will override the Script with the content of the file. No


JSR223 Action are samplers, and as such have an Ok/Ko result and a response time. If you do not want any of this, you can add the following inside the JSR223 action: SampleResult.setIgnore();.


The JSR223 allows you to execute a script, written in various languages: JSR223 Language

More information is available in the JMeter documentation.


In this page, we will focus on Groovy, Java and JavaScript as they are the most common languages.


Let's take an example to understand how these work:


We have 3 parameters, separated by spaces:

  • first
  • second
  • last

Script and its resulting log messages"Number of parameters: " + args.length)"Parameters array: " + args)"All parameters: " + Parameters)"First parameter: " + args[0])"Second parameter: " + args[2])
INFO JSR223: Number of parameters: 3
INFO JSR223: Parameters array: [first, second, last]
INFO JSR223: All parameters: first second last
INFO JSR223: First parameter: first
INFO JSR223: Second parameter: last


The following variables can be used in any JSR223 script:

name Description Example
ctx Execution context ctx.isSamplingStarted();
vars Variables in the scope vars.get("counter");
props System properties props.get("START.HMS");
log Log messages in the log file"Hello World!");
SampleResult Points to the current SampleResult SampleResult.setIgnore();
OUT Console output OUT.println("Hello World!");
sampler Pointer to the current Sampler. sampler.addArgument("name", "value");

JMeter variables and functions

The underlying JMeter will process variables and functions before passing the script field to the interpreter.

We always cache-compile groovy scripts for performance, and you should be extra careful with that language.

Before and after cache-compilation

int starttime = ${__time()}
int starttime = 1604320548420

It may not seem like much but after this, the cache-compiled version is going to be used for the rest of the test. Which means the date is not updated anymore.

In these situations here are some scripted alternatives:

Action type Raw Groovy Cache-compiled Groovy
Variable use ${myvar} vars.get(myvar)
Functions ${__time()} Pass ${__time()} as a Parameter


Additionally, a function even if commented out in your script might cause an error if it is not properly configured. The reason being that JMeter will process it before the script is interpreted, not knowing if it is commented out.

Pre/Post processors


Script processors can be attached to a request, in which case the order of actions will be:

  • Pre-processors from top to bottom
  • HTTP Request
  • Post processors from top to bottom

Here's an example with a bunch of processors:


Each processor will log its name to the standard log, and the result is:

Processors order log

ERROR o.a.j.m.J.77b6b9ab-54b7-40be-a219-f3cefa0a0f62: Pre Processor 1
ERROR o.a.j.m.J.ab0724ab-6845-4ef9-aa05-52d75ab18e3f: Pre Processor 2
INFO o.a.j.r.Summariser: summary =      1 in 00:00:01 =    0.8/s Avg:   186 Min:   186 Max:   186 Err:     1 (100.00%)
ERROR o.a.j.e.J.e00f2117-6910-4298-89ab-c384dfc50d6c: Post Processor 1
ERROR o.a.j.e.J.5b3e7453-7082-417f-a79a-3724e75768fc: Post Processor 2
ERROR o.a.j.e.J.1a99c95a-265c-4156-8083-6ce438b3e91b: Post Processor 3


Processors will apply to all the requests that are at the same level than them or below.

To fully understand the meaning of this sentence, we need to understand that these situations are equivalent:

Identical situations




Since there's only one request on the same level or one level below in all these situations it doesn't matter where the processor is.

And another example where the situation is not equivalent:

Different situations


Here the processor applies only to the first request, but if we move it at the same level then it applies to both:


What can be counter intuitive is that its vertical position doesn't matter (it could be first or last, the effect would be the same), only its horizontal (indentation) position enters into account.

Best practices

Script actions can drastically increase the weight of your virtual users, try to use them sparingly. You have to remember that they will be executed by every virtual user, every iteration, and so their effects multiply quickly.

For reference, we place 1000 virtual user on each load generator in a standard OctoPerf test. On fast paced tests that means your JSR223 scripts could run thousands of times per minute.

Use groovy

Use Groovy because it's the only language that can be compiled in JMeter. That makes it far more efficient than all others.

Beware of processor placement


Do not use Pre/Post processors at the root level of your virtual user, otherwise they would be executed for EVERY sampler, including resources and third party calls.

If you have to do it anyway, keep it as simple as possible, a one line script can already slow down your execution significantly. Especially in combination with one of the other topics below.

Don't reinvent the wheel


Avoid Actions that can be performed by other well optimized samplers/processors.

Also check if a function exists that could answer your need. And remember that functions can be passed as parameters to avoid cache effects.

Avoid disk operations

Disk Read/Write operations can quickly overload the hard drive of the load generators. They are optimized to provide a lot of CPU and memory but the hard drive is usually not efficient enough for hundreds of read/write operations per second.

It is even worse when you write from the same file in every virtual user. You're likely to get a lot of write wait time because the file can only be accessed by one of the virtual users at a time. In that case all other users wait in line to access it and write their changes.

Disable logging


Excessive logging can also overload the hard drive, even when it doesn't it will still slow down your hit rate significantly. But most importantly we only store up to 100 Mb of zipped test logs. So if you go over this limit the test log will not be stored in OctoPerf's report at all.

Do not load large files

Avoid loading huge quantity of data in memory. For example large files or functions like prev.getResponseDataAsString().

You can generate an important memory overhead quickly since it will be multiplied by the number of concurrent users doing so. This can also overload the CPU if the worst happens and the Heap memory is overloaded.

No dependence on third parties

Avoid sending calls over the network like fetching a value from a 3rd party. If there's any issue, the call may fail thus creating a huge waiting time and you will have a hard time debugging that.

It's easier to do these things once before or after the test and to isolate them into a setup or teardown thread. This way you can tell when they are failing and they won't impact your test as much.

Be careful of the usual suspects


Pay attention to loops and other pieces of code that require a long execution time, they can also slow down the hit rate of your virtual users significantly.

Especially in combination with one of the other items above.