Load tests and release budgets
Metrics → Load tests evaluates results produced by your existing k6 runner. Create a suite, choose a minimum request count and performance limits, then import a report or upload it from CI. The platform stores results; it never runs a load test or executes your script.
Prepare a suite
Open Suites and budgets in the intended environment. Give the suite a stable key such as checkout. Start with HTTP duration p95, failed-request percentage and a minimum number of requests. Each suite supports eight rules. A new suite requires a recent passkey and Metrics write access.
A report can pass only when completion is confirmed, the request minimum is met and every configured measurement is present. A failing numeric rule or reported source threshold fails the budget. Missing metrics and insufficient evidence remain inconclusive. Checks are displayed separately because a failing k6 check does not necessarily fail the runner's own thresholds.
Export the summary
Add a file output to your existing k6 script:
export function handleSummary(data) {
return { 'summary.json': JSON.stringify(data) };
}
The importer accepts the legacy handleSummary object and machine-readable summary version 1.0.0. It does not accept the line-by-line --out json event stream. Configure the needed trend statistics in your runner; absent p99 or other measurements stay missing.
k6 2.2.0 was exercised locally with both summary formats. Its machine-readable output uses snake-case metadata and p95, while the published schema example uses camel case and p(95); both forms are supported. The tested machine-readable output omitted p99 and source thresholds, even when requested, so use the legacy summary when those fields are required. The detail page explicitly identifies omitted source thresholds. See the official custom-summary documentation and versioned schema.
Upload from CI
Create a dedicated Management API token with write scope and metrics.write. Public and secret ingest keys cannot import reports. Store the token in your CI secret manager. Do not embed it in the load-test script or send it to the system under test.
After the runner has finished, prepare an upload envelope. Supply a fresh UUID for an actual new run, and keep it unchanged for retries:
{
"runId": "11111111-1111-4111-8111-111111111111",
"suite": "checkout",
"release": "1.4.0",
"engineVersion": "2.2.0",
"workloadHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"finishedAt": "2026-09-08T01:00:00Z",
"completion": "completed",
"summary": {}
}
Replace the example values and summary with the actual full summary object. completion is completed, aborted or unknown; only report completed when the runner confirms it finished. Finish time must be within retained history. The workload hash should digest a reviewed manifest containing the script digest, load options, target dataset/version and runner resources. A matching digest is your runner's assertion of comparable conditions, not independent attestation.
Send the envelope after exporting the real summary.json, using your CI's JSON tool to preserve types:
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $SPM_MANAGEMENT_TOKEN" \
-H 'Content-Type: application/json' \
--data-binary @upload.json \
"$SPM_HOST/api/v1/apps/$SPM_APP/metrics/load-tests?env=$SPM_ENV"
SPM_APP is the application UUID or organization-slug/application-slug. The response includes id, runId, duplicate and verdict. HTTP success confirms storage, not a passing budget: require verdict.status === "passed" in your CI gate. Treat failed and inconclusive separately. Preserve upload.json unchanged for a retry; conflicting reuse of a run ID returns 409. Policy edits do not rewrite old verdicts or exact retries.
A read token with metrics.read can retrieve the result at GET /api/v1/apps/{app}/metrics/load-tests/{id}?env=.... CI tokens do not change suites or baselines; those controls stay in the console with a fresh passkey.
Compare releases
Open a completed, passing report and select Use as baseline. Comparisons require the same suite, environment, workload hash, k6 major version and summary format. Different workloads show an explanation instead of percentage changes. Missing and zero baseline values have no percentage. Each percentile belongs to one run; the platform never averages percentiles across reports.
The import-time result is frozen. Changing a budget affects future imports, and changing a baseline changes the current comparison. Neither action changes the recorded run measurements.
Storage and privacy
Only approved built-in aggregate metrics, check/threshold counts and technical run metadata are retained. Raw script content, paths, URLs, check names, group names, tags and custom metrics are discarded. Use technical release names without customer details. File names remain in your browser.
Bounds per environment: fifty suite keys, 200 new reports/day, 5,000 retained reports and 64 MiB. A source summary is limited to 256 KiB and normalized retained content to 24 KiB. Retention is the shorter of thirty days and application retention, applied immediately on reads. Worker cleanup runs in bounded batches.
Pausing a suite refuses new reports and preserves exact retries. Deleting a report clears it as a baseline and leaves a thirty-day replay tombstone. Fresh passkeys, tenant permissions, CSRF and audit protect console changes. Provider deployment and real production load generation are not part of this integration's local verification.