Scripting

Load Test specs have two lifecycle script slots — Before All and After All — that run once per test run (not once per VU iteration). They use the exact same scripting engine,tg.* API and snippet library as the Flow Runner.

When They Run

  • Before All — runs once when you press Start, before any VUs are spawned. Use it to log in, mint a token, warm a cache, or seed flow variables that every VU will read via {{flow.key}}
  • After All — runs once after every VU has finished and the results have been aggregated. Use it to notify a channel, POST a report to an HTTP endpoint, or trigger a downstream job

Single execution, not per-VU: these scripts run exactly once regardless of how many VUs the test is configured for. For hot-path logic that should run on every iteration, use a step's preScript or postScript instead — see the Steps section above.

The Script Editor

Clicking Before All or After All in the Steps rail opens a dedicated editor panel with three zones:

  • Header bar with a ▷ Try button that runs the script once in isolation against the current environment, so you can verify it works before kicking off a real test
  • CodeMirror editor with JavaScript syntax highlighting and autocompletion for the tg.* API
  • Snippets panel on the right that can be collapsed into a thin chevron strip when you need more editor space
  • Script console below the editor showing console.log output and any errors from the most recent Try run

The tg.* API

The same runtime that powers Flow Runner lifecycle scripts is available here. What's accessible depends on whether you're in Before All or After All — the export helpers only make sense after results exist.

NamespaceMethodsBefore AllAfter All
tg.flowget(key) / set(key, value)
tg.environmentget(key) / set(key, value)
tg.export.json() → string
tg.export.html() → string
tg.export.pdf() → Promise<Uint8Array>
fetch / consolestandard web globals

Autocompletion in the editor reflects this — After All gets the full tg.export.* surface, Before All does not.

Before All Snippets

The built-in Before All snippet library matches the Flow Runner list. Click any snippet to insert its code at the end of your script:

SnippetWhat it does
GET requestFire a basic GET with fetch
POST requestSend a JSON POST body
Register userCreate a new user with a random username template
Login & set tokenLogin and store the token as tg.flow.set("token", …)
Set flow variablePersist a value every VU can read via {{flow.key}}
Get environmentRead an env variable with tg.environment.get
Set environmentWrite an env variable with tg.environment.set
Console logLog to the script console below the editor

After All Snippets

After All ships a different snippet list tailored to reporting rather than setup:

SnippetWhat it does
GET requestBasic GET (same as Before All)
POST requestBasic JSON POST
Slack notificationPOST to a Slack incoming webhook to announce the run finished
POST JSON reportSerialize the run with tg.export.json() and POST it
POST HTML reportRender the HTML report via tg.export.html() and POST it (useful for email APIs)
POST PDF reportGenerate the PDF via await tg.export.pdf() and POST the binary
Get flow variableRead a value that Before All or a step stored
Console logLog to the script console

Fire-and-forget is fine here: After All runs after the test is over and results are captured, so a slow report upload won't affect the run's metrics. The Try button also works here — it runs against the last completed run so you can iterate on your report code without re-running the load test.

Same Engine as Flow Runner

Under the hood, Before All / After All use the exact same executeLifecycleScript service that Flow Runner uses. That means everything you learned in the Flow → Scripting section of this guide applies here: the runtime, the autocomplete, the console output, the environment resolution pipeline. The only thing that's different is the snippet list, which is tuned for load-test scenarios.