JMeter Groovy Scripting: Beyond the GUI

How to use JSR223 Groovy scripting in JMeter for custom logic that the built-in components can't express, with practical examples.

· By perf-test.com Editorial · AI-assisted
jmetergroovyscripting

JMeter’s GUI components cover most common needs, but custom logic — complex data transformation, conditional behavior beyond what an If Controller expresses cleanly, or integrating with an external system — eventually needs real code. The JSR223 Sampler/PreProcessor/PostProcessor elements, scripted in Groovy, are the standard way to do this.

Why Groovy over BeanShell or the legacy Java element

JMeter historically supported BeanShell for scripting; JSR223 with Groovy is faster (Groovy scripts can be compiled and cached, unlike interpreted BeanShell) and is the currently recommended approach for any new custom scripting. Avoid BeanShell for new scripts unless you have a specific compatibility reason.

Where JSR223 elements fit

  • JSR223 PreProcessor — runs before a sampler executes; useful for computing a value the sampler needs (a signed request hash, a dynamically constructed payload).
  • JSR223 PostProcessor — runs after a sampler’s response arrives; useful for custom extraction logic beyond what the built-in extractors support, or for custom validation logic.
  • JSR223 Sampler — a standalone sampler running arbitrary Groovy, useful for steps that aren’t really HTTP requests at all (computing a value, calling a local library, talking to a system JMeter has no native sampler for).

A practical example: HMAC-signed requests

Some APIs require a request signature computed from the request body and a secret key. A JSR223 PreProcessor can compute this signature in a few lines of Groovy and store it as a JMeter variable for the HTTP sampler to include as a header — something no built-in component handles directly:

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

def secret = vars.get("apiSecret")
def payload = vars.get("requestBody")
def mac = Mac.getInstance("HmacSHA256")
mac.init(new SecretKeySpec(secret.bytes, "HmacSHA256"))
def signature = mac.doFinal(payload.bytes).encodeHex().toString()
vars.put("requestSignature", signature)

Accessing JMeter context from Groovy

Inside a JSR223 element, vars (JMeter variables), props (JMeter properties), log (JMeter’s logger), and prev (the previous sample result, in PostProcessors) are all available without extra imports — covering most of what scripts need to read/write test state or inspect the last response.

Performance consideration

JSR223 with Groovy, using “compiled” mode (cache the compiled script rather than re-parsing it every iteration — the default behavior when a script is provided directly rather than via an external file reference that changes), is fast enough for most uses. Very hot-path scripts running on every single sample, at very high iteration counts, are worth benchmarking standalone if they involve anything non-trivial (cryptography, large string processing) since they do add real CPU cost to the load generator itself.

When not to reach for Groovy

If a built-in component (Extractor, Assertion, Controller) already does what you need, prefer it — it’s more maintainable for the next person reading the test plan, and avoids accumulating scattered custom code across a script that’s otherwise GUI-configured.

Takeaway: JSR223 Groovy is the escape hatch for the genuinely custom 10% of logic a load test sometimes needs — reach for it specifically when a built-in component can’t express what you need, not as a default scripting style.

Discussions coming soon.

Comments are powered by Giscus (GitHub Discussions). Enable them by configuring GISCUS in src/consts.ts — see giscus.app.