@cloudbeat/atlas-recorder
v0.4.0
Published
Record a browser session and turn it into a JMeter load-test plan
Readme
@cloudbeat/atlas-recorder
Record a browser session and get a JMeter test plan out of it.
You click through your application in a real browser — log in, search, check out —
and the recorder writes a .jmx you can run as a load test. It captures the
requests your app actually made, skips the noise, and wires up the values that
have to change on every run (CSRF tokens, session ids) so the script still works
when you replay it with hundreds of users.
Install
npm install -g @cloudbeat/atlas-recorderThis downloads a private Chromium build (a few hundred MB) that the recorder uses for capture. It won't touch or interfere with the browsers you already have.
Requires Node.js 18 or newer.
Record a scenario
atlas-rec record https://example.com -o checkout.jmx -n "Checkout"A browser window opens with a small control panel in the corner. Click through
your flow, then press Stop. The plan is written to checkout.jmx.
Each thing you do — a click, a form submit, a page change — becomes a labelled transaction in the plan, with the requests it triggered grouped underneath. That way a report tells you "Checkout took 3.2s", not just which URLs were slow.
While recording you can, in the control panel:
- rename a transaction, so the report reads in your language rather than the app's URLs
- ➕ New to start a new transaction before you click, when one page really holds two steps worth measuring separately
- expand a transaction and exclude or delete individual requests you don't want in the test
- ⏸ Pause while you set something up you don't want recorded
- name the whole scenario
Your recording is saved when you press Stop, when you close the browser window, and on Ctrl+C — closing the window by mistake won't lose it.
Add a scenario to an existing plan
Point -o at a plan that already exists and the new recording is added to it
as another thread group, leaving what's already there untouched:
atlas-rec record https://example.com -o suite.jmx -n "Checkout"
atlas-rec record https://example.com -o suite.jmx -n "Search" # adds a secondA .bak copy is written before the file is changed.
-t (threads) and -l (loops) only apply when the file is being created — they
are not touched when adding to an existing plan.
Recording behind a login
Two ways to skip a login you don't want to record every time.
Reuse a signed-in session. With --profile, the session is saved when you
stop and reloaded next time, so you start already logged in:
atlas-rec record https://app.example.com -o app.jmx --profile ./session.jsonBring cookies from your own browser. Export them and pass --cookies. Files
saved by the usual browser cookie extensions are understood, as is a raw
Cookie: header pasted into a file:
atlas-rec record https://app.example.com/home -o app.jmx --cookies ./cookies.jsonWhat ends up in the plan
Kept: the requests your application makes — pages, API calls, form posts, and
CORS preflights (marked (OPTIONS) so you can spot them).
Skipped: images, stylesheets, fonts, and known analytics traffic. These inflate a load test without telling you anything about your application. If you need one of them, include it from the control panel while recording.
Values that change every run are handled for you. If a request sends
something it was given earlier — a CSRF token, a session id, an item id from a
search result — the recorder finds where that value came from and pulls it out of
the live response at run time instead of replaying the recorded one. Each of these
gets a check attached, so if the value ever stops coming back the sample fails
loudly rather than quietly posting a stale token. Turn this off with
--no-correlate.
Values that look like a timestamp are replaced with JMeter's own clock so they're
current on every request (--no-timestamps to keep them as recorded).
Every web page is checked by its title. When a page you visited had a title,
the plan checks that the same title comes back on every run, so a login screen or
error page served in place of the real one fails the sample instead of counting as
a success. If your titles change from run to run (a user name, a date), turn this
off with --no-title-assertions.
Pauses between steps are recorded and added as think-time, but switched off,
so the plan runs flat out until you decide otherwise. To use them, enable the
Settings - Sleeps block in the plan and set the durations you want.
A .capture.json file is written next to your plan holding the raw session. You
don't need it to run the test — keep it if you want to re-generate the plan later,
or pass --no-capture to skip it.
Options
| Option | Meaning |
|--------|---------|
| -o, --out <file> | Where to write. An existing plan is added to; otherwise created |
| -n, --name <name> | Name for the scenario (also editable while recording) |
| -t, --threads <n> | Number of users — only when creating a new plan |
| -l, --loops <n> | Iterations per user — only when creating a new plan |
| --profile <file> | Save and reuse a signed-in session between recordings |
| --cookies <file> | Start the recording already signed in, using exported cookies |
| --correlations <file> | Pin named parameters to a value of your choosing instead of detecting them, e.g. { "authToken": "${authToken}" } |
| --no-correlate | Replay recorded values as-is instead of detecting changing ones |
| --no-timestamps | Keep recorded timestamps instead of using the current time |
| --no-title-assertions | Don't check that each page returns its recorded title |
| --capture <file> | Where to write the raw session file |
| --no-capture | Don't write the raw session file |
| -f, --format <fmt> | Output format. jmeter is currently the only one |
| --control | Also accept commands from atlas-rec while you record |
Threads and loops are written into the plan as settings you can override when
you run it (-Jthreads=50), so a plan recorded with one user can be sized up
without editing it.
Letting an AI assistant do the clicking
The recorder can be driven by a program — a Claude Code or Copilot session, or a
script of your own — instead of by hand. Everything below is optional: plain
atlas-rec record is unchanged, and while a program is driving, your own clicks
in the window are still recorded.
atlas-rec start https://example.com -o flow.jmx # opens the browser, returns a session
atlas-rec snapshot # what is on the page right now
atlas-rec click --text "Sign in" # act on it
atlas-rec fill "[email protected]" --selector "#email"
atlas-rec tx new "Checkout" # name the step that comes next
atlas-rec state # what has been recorded so far
atlas-rec stop # write the planAfterwards, the recording can be re-read and re-rendered without repeating it:
atlas-rec inspect flow.capture.json # transactions, hosts, response codes
atlas-rec suggest flow.capture.json # changing values it would detect, and why
atlas-rec generate flow.capture.json -o flow.jmx --correlations rules.jsonThese commands print JSON. They talk to the browser over a local-only channel that nothing outside your machine can reach, and they only work while a recording you started is open.
If you use an AI assistant, atlas skills install (from
@cloudbeat/atlas-cli)
teaches it how to use all of this — including when to hand the browser back to
you.
Using it with the Atlas CLI
If you use @cloudbeat/atlas-cli,
it can drive the recorder and put the result straight into a project:
atlas record https://example.com -o flow.jmx --upload -p MY-PROJECTThe recorder is a separate package precisely so CI machines — which run tests but never record them — don't have to download a browser.
Things worth knowing
Check the plan before running it at scale. The recorder captures a single pass through your app. Anything that only appears sometimes (a cookie banner, an A/B variant, a retry) is recorded only if it happened while you clicked.
One recorded click can be two requests when a page redirects. The redirect is followed and the destination is also recorded on its own, so a redirecting step can hit the destination twice per iteration. Delete the duplicate from the control panel, or from the plan afterwards, if that matters for your numbers.
Opening the app is one transaction. Everything up to your first click — redirects off the start URL, a sign-in hop, a page that failed and reloaded — is recorded as a single step, named after the page you end up on. Renaming it in the control panel keeps your name.
Single-page apps are handled — in-app route changes are detected. A page change that your click caused belongs to that click, so one action stays one transaction even when the app calls the server first and moves a second or two later. A page you open yourself, after a pause, starts a new transaction. Where the split lands somewhere you did not want, use ➕ New to set the boundary.
If a recorded value can't be found at run time, the check attached to it fails the sample and names the value, which is your signal that the flow changed or the step that produced it wasn't recorded.
