Spitfire
SpitfireDistributed load testing · self-hosted

Where does your system break?

Find it before your customers do. Spitfire raises the load step by step, shows where latency starts to bend, and marks the run as failed the moment a threshold breaks. Tests are built in the browser, no code needed.

curl -fsSL https://spitfire.tr/install.sh | bash -s -- dockerone command: Docker is all you need
virtual users
420
req/s
3,780
p95
194ms
p(95)<500
✓ pass
05001000150002004006008001000p95 msVUs →p(95)<500breaking point ≈ 563 VUs
example system · illustrative
Producttest editor

Fill in a test like a form.

Scenario, stages, steps and thresholds on one screen. Behind it the same test is kept as JSON, so you can also write it as a file.

An illustration of the interface; real screenshots to follow.

Demoa real run

After you press Run.

40 virtual users, two locations, four steps: the charts fill second by second, thresholds are evaluated live, and the per-location and per-step breakdown is ready at the end.

What can it do?

Beyond HTTP, in the same test

A user journey calls the API, drops a message on a queue and queries the database. Spitfire loads all of them as steps of one test.

HTTP/HTTPSHTTP/2WebSocketSSEgRPCKafkaMQTTAMQP · RabbitMQRedisPostgreSQLMySQLSQL ServerOracleMongoDB
Multi-locationone run

One run, several cities.

Split the load across locations by percentage and see each location's latency separately. Remote runners connect outbound to the controller over TLS with key pinning, so the load servers need no inbound ports.

A runner installs as a Docker image or as a single binary with a systemd unit; the UI prepares the install command.

controller
web UI · REST API · Postgres
gRPC/TLS :8471
runners dial out and verify the certificate pin
--ca-pin sha256:9f2c…e41a
istanbul
3 runner · Docker
60%
frankfurt
2 runner · systemd
40%
Comparisonk6 · JMeter · Locust

Why Spitfire?

Spitfirek6JMeterLocust
To write a testWeb editor or JSONJavaScriptDesktop GUIPython
Single sign-on (OIDC, LDAP)✓ group → role mapping— cloud edition——
Self-hosted team UI✓ roles, groups— cloud edition—~ no users
SQL · Kafka · MQTT · Redis · MongoDB✓ built in~ extensions~ partly~ in code
Several locations in one run✓ by percent— cloud edition~ manual~ manual
Tests from OpenAPI / Postman / HAR✓ in the UI, auto-correlation~ separate converters~ recording proxy, plugins—
Production write guard✓———
Shareable report✓ PDF, HTML, link~ HTML only~ HTML only~ HTML only
Scheduled runs + Slack / Teams / e-mail✓ built in, PDF attached— cloud edition~ via a CI server—
Alert on a regression against the baseline✓ Slack, Teams, e-mail, webhook———
Responses of failed requests✓ samples on the run page~ by logging in code~ with a listener~ error text only
Audit log✓ tamper-proof———
Pass/fail exit code for CI✓ k6-compatible, on your runners✓~✓

Compared against each tool's open-source edition. Detailed comparison →

InstallDocker · Kubernetes

Your first test in three steps.

All you need is Docker (plus kubectl for Kubernetes). No Go or Node required.

STEP 1

Install

curl -fsSL https://spitfire.tr/install.sh | bash -s -- docker

Starts Postgres, the controller, the web UI and 2 runners.

STEP 2

Create the admin

Setup code: K7QM-2XRT-9WHP

Open the address printed at the end and create the first admin with the one-time setup code.

STEP 3

Add a test, press Run

Tests → New → Run

Have Swagger/OpenAPI or Postman? Tests → From API document. For another location, Runners → registration key; the command is ready there.

What it doesat a glance

From load to verdict, in one place.

Tests, connections, runners and every run's result live in one interface. Your team looks at the same number.

Real user journeys

Log in, list, order. A value from one response becomes the next step's variable, and every response is checked.

extract $.tokenBearer {{token}}check status = 200

Tests from your API docs or a browser recording

Point it at an OpenAPI 3, Swagger 2.0 or Postman collection, or a HAR file recorded in the browser; the requests you pick become steps. In a recording, tokens and ids a response returned and a later request sent back become variables automatically, and pauses become think time. Methods that change data need a separate approval.

OpenAPI 3Swagger 2.0PostmanHARPOST · PUT · DELETE → approve

Realistic data and sessions

Upload a CSV and every iteration takes a row: in order, at random, or unique across runners. Each virtual user keeps its own cookies, so logged-in web flows work without passing headers by hand.

{{users.email}}sequential · random · uniquecookie jar

Load from several cities

Split a run across locations by percentage. Remote runners dial out over TLS with key pinning, so no inbound ports are needed.

istanbul 60%frankfurt 40%--ca-pin sha256:…

Scheduled runs, instant news

Run a test every night or every weekday morning. When a threshold breaks, a run fails or a scheduled run does not start, Slack, Teams or e-mail hears about it; the e-mail carries the PDF report. When a run is clearly worse than its baseline run (p95, p99, error rate, requests/s), you hear before any threshold breaks: while the system slows down, before users notice. Only on problems and only for the tests you pick, if you like.

0 2 * * *SlackTeamse-mail + PDFp95 +39% → run.regressed

Sign in with the company identity

Single sign-on with Entra ID, Okta, Google, Keycloak (OpenID Connect) or Active Directory / LDAP. Accounts open on first sign-in; the admin role and group memberships come from the identity provider's groups. If you like, password sign-in stays for admins only.

OIDC + PKCELDAP · ADgroup → role

A guard against production writes

SQL and MongoDB writes and dangerous Redis commands are flagged, and nothing runs until each step is approved. Passwords stay in an encrypted vault.

SELECT ✓INSERT → approveFLUSHALL ✕

Live results, compared with history

Per-second charts with per-step and per-location breakdowns. Mark a baseline and regressions show side by side.

p50 · p90 · p95 · p99baseline

Not just "500": what the server said

The run page keeps samples of failed requests: a few per step and outcome, with the target, the error, the failed check, a few response headers and the first 2 KB of the body. Tokens in the address are masked, cookies are never kept, and steps that do not fail cost nothing.

503 · card service unavailabletoken=***2 KB

Every save is a version

The test page lists versions, who saved them and the diff with the current one; an old version comes back as a new one in one click. When two people edit the same test, the second save warns instead of overwriting. Every run knows which version it ran.

v7 → v8diffrestore

APIs that want a client certificate

When internal or partner APIs are protected with mTLS and a private CA, put the certificate and key in the connection vault once; HTTP, WebSocket and SSE steps pick it. The key is stored encrypted and never enters the test definition; the Test button checks the certificate has not expired.

mTLSprivate CAclient.pem · key 🔒

A report ready for your manager or customer

Every run becomes an HTML or PDF report in one click: charts, thresholds, steps, locations and the change against the baseline run. Send it to someone without an account through a time-limited, revocable link; raw data downloads as CSV.

PDFHTMLCSVshare linkTR · EN

A release gate in CI

GitHub Actions, GitLab CI or Jenkins run the saved test on the controller with an API token and pass or fail on its thresholds; the UI prepares the steps. The CLI also runs the same test file without a controller. Exit codes match k6.

spitfire cloud runSPITFIRE_TOKENexit 0exit 99 · threshold

Talks to your monitoring

Run events go out as signed webhooks, live metrics over OTLP and Prometheus. In METI, the AI attributes symptoms inside the test window to the load test: no false alarm, no wrong root cause.

webhookOTLPPrometheusMETI AI RCA

Built for teams

Admin and user roles; groups grant run rights per test. The audit log keeps who did what and when, tamper-proof and exportable to CSV. The interface speaks Turkish and English.

audit logappend-onlyCSV

Start free

License keys are verified offline; Spitfire never phones home.

Free edition

0 ₺no key needed
  • Concurrent virtual users100
  • Requests / second500
  • Run length30 min
  • Runners · locations per run2 · 1
  • Active users3
  • Per-second results kept30 days
Install now

Licensed edition

—
  • Concurrent virtual usersunlimited
  • Requests / secondunlimited
  • Run lengthunlimited
  • Runners · locations per rununlimited
  • Active usersunlimited
  • Per-second results keptunlimited
Buy now

Frequently asked

Is my test data sent anywhere?
No. The controller, runners and results run on your own servers, and the license key is verified offline.
Do I need to write code?
No. A test is built step by step in the web editor. If you prefer, write the same test as a JSON file and run it with the CLI.
Can I test live screens that use WebSocket or Server-Sent Events?
Yes. In a WebSocket step every virtual user keeps one connection, like a browser tab: it sends a message, waits for the reply or for a message the server pushes (containing a given text), and the message goes to checks and extraction. The connection carries the cookies from login and reconnects on the next step if it drops; the handshake is measured as ws_connecting. An SSE step opens the event stream and reads until the given number of events (by type or content) arrived; the time to the first event is the sse_time_to_first_event metric. Both can have thresholds.
What if a runner or the controller drops during a run?
A runner whose connection drops and comes back within 10 seconds carries on; if it does not, the run stops, or continues without it if the test says so. If the controller is stopped (an update, a restart), it stops the active runs and stores their results first; if it goes down unexpectedly, the run closes as interrupted when it starts again. Either way the runners drop the load at once and webhook receivers get the end notice. Stop and thresholds work even while the database is slow; if some data could not be stored, the run says so as a warning.
Can I run a fixed number of operations instead of a duration?
Yes. "Shared iterations" splits a fixed number of iterations among the VUs; "per-VU iterations" has every VU run the same number. The test ends when the work is done, with a max duration as the ceiling. Across several runners the work is split exactly by each runner's share of the VUs. Good for data loading, smoke tests and one-off jobs.
I have a Swagger document, a Postman collection or a browser recording. Do I write the test from scratch?
No. Tests → Import API / HAR: give an OpenAPI 3, Swagger 2.0 or Postman v2.x collection, or a HAR recording (browser DevTools → Network → "Save all as HAR"), and pick requests. In a HAR, static files are dropped, tokens and ids become variables automatically, and cookies stay separate per virtual user. Only GET requests are taken by default; POST, PUT/PATCH and DELETE need a per-group approval plus the target host name, the approval is written to the audit log, and the test asks again on every run.
Our monitoring alarms during load tests. What can we do?
On the Integrations page, announce run start and end with a webhook and send live metrics over OTLP or Prometheus. With METI, "Connect to METI" is enough: symptoms that start on a tested host inside the test window are attributed to the load test by its root-cause analysis.
Can people sign in with their company account (Entra ID, Okta, Active Directory)?
Yes. On the single sign-on page set up your OpenID Connect provider (Entra ID, Okta, Google, Keycloak…) or your LDAP / Active Directory. Accounts can open on first sign-in, or only accounts an admin created may enter; you can limit sign-in to groups, map admin groups to the admin role and sync memberships into Spitfire groups of the same name. Password sign-in can be left to admins only; LDAP passwords are never stored in Spitfire.
Can a test run every night and tell us when something is wrong?
Yes. On the test's page, Schedule: pick a cron and time zone; the run starts with the rights of whoever created the schedule. Under Integrations → Notification channels add a Slack, Microsoft Teams or e-mail channel and turn on "Only notify on problems": you hear when a threshold breaks, a run fails, or a scheduled run does not start (no runners, missed). The e-mail carries the run's PDF report.
How do I send results outside the team?
On the run page, Report → Download PDF or Share link. The link shows the HTML and PDF report without signing in; it lasts 1–90 days, can be revoked at any time, and every view is written to the audit log. Reports come in Turkish or English.
How do I run tests from my CI/CD pipeline?
Create a token under profile menu → API tokens, add it to the pipeline as the SPITFIRE_TOKEN secret, and run spitfire cloud run "Test name" in a step. The CLI comes from the controller or the Docker image; the CI button on a test's page prepares GitHub Actions and GitLab CI steps. The step exits 0 (passed) or 99 (thresholds failed).
Where can I install it?
Docker or Kubernetes, on amd64 and arm64; Linux, macOS and Windows (Docker Desktop, one PowerShell command). A runner in a remote location can also run without Docker: with systemd on Linux, as a Windows service on Windows.
I lost the setup code shown after installation. What now?
The code stays valid until the first admin exists and is stored: SPITFIRE_SETUP_CODE in ~/spitfire/deploy/docker/.env on Docker, the spitfire-secrets Secret on Kubernetes. The controller log also prints setup_code=, and re-running the installer shows the same code.
Our API wants a client certificate (mTLS); can I test it?
Yes. Save the certificate, the key and, if needed, the private CA to trust once under Connections → Client certificate (mTLS); HTTP, WebSocket and SSE steps pick it under "Client certificate". The key is stored encrypted and never enters the test definition; saving checks the certificate and key belong together, and the Test button checks the certificate has not expired.
How long are results kept?
You decide: the Data retention setting on the License page keeps per-second chart data, run logs and error samples (90 days by default), whole runs and the audit log for their own number of days; what you leave empty is kept forever. Tests' baseline runs are never deleted, and the page shows what would go before you save. The audit log is append-only: only entries older than 30 days are deleted this way, and the deletion is recorded too.
What happens when the license expires?
A 14-day grace period starts and the application says so. After it Spitfire keeps running within the free edition's limits; your tests, runs and reports are not deleted. Paste the new key on the License page and the limits open again at once, without reinstalling.
How do I hear about new releases, and is updating hard?
The application tells you about a new release itself (from a signature-checked release list), and security updates are marked. Updating is the same single install command: the database is backed up first and the settings kept; if anything goes wrong, --rollback returns to the previous release and its data. Runners installed without Docker update themselves from the Runners page or with auto-update.
What does the free edition limit?
Only scale: 100 virtual users, 500 requests/s, 30-minute runs, 2 runners, 1 location, 3 users and 30 days of results. Features are not restricted.