When running load tests, especially on complex systems like SaaS productss, it’s not enough to just measure all requests together. You want insight into specific endpoints, groups of requests, or types of users. That’s where tags come in.
In this post, we will learn how to:
- Attach tags to requests
- Define thresholds for each tag
- Use groups to combine multiple requests
- Analyze per-tag metrics to see which endpoints are fast, slow, or failing
Table of contents
Open Table of contents
Why Tags Matter
In k6, tags are labels you attach to requests. They allow you to:
- Apply thresholds per endpoint
- Track metrics for different user flows
- Analyze results with granularity
Using tags, you can tell k6:
I want to make sure the login endpoint is always fast, even if other endpoints are slower.
Without tags, thresholds are applied globally.
Example:
http_req_duration: ["p(95)<500"]
- This applies to all requests.
- If a heavy report endpoint spikes to 2 s, your login endpoint could fail the test even if it’s fast.
Tags solve this by allowing endpoint-specific thresholds.
How to Use Tags in k6 Requests
You can attach tags to individual HTTP requests via the tags option:
const loginRes = http.post(
"https://fakeloadtest.com/auth/token/login/",
loginPayload,
{ headers: commonHeaders, tags: { name: "login" } }
);
// 2. Get Product list (protected endpoint)
let products = http.get("https://fakeloadtest.com/api/products/",
{ headers: withAuth, tags: { name: "products" } }
);
tagsis an object of key/value pairs.- Commonly, we use
nameto identify the endpoint or user flow.
Using Multiple Tags
You can have multiple tags per request:
let products = http.get("https://fakeloadtest.com/api/products/",
{ headers: withAuth, tags: { name: "products", method: "GET", user: "admin" } }
);
name→ endpointmethod→ HTTP methoduser→ user type
Applying Thresholds to Tags
Once requests are tagged, you can define per-tag thresholds in options:
export const options = {
thresholds: {
"http_req_duration{name:login}": ["p(95)<400"], // Single tag
"http_req_duration{name:products,user: admin}": ["p(95)<600"], // Multi tag
http_req_failed: ["rate<0.01"],
},
};
- Login → 95%ile response time must be faster than 400 ms
- products tag with admin user → 95%ile response time must be faster than 600 ms
- Global error rate → less than 1%
Tags let you enforce SLAs for each critical endpoint without affecting the entire system.
This is extremely useful for role-based testing or multi-tenant SaaS productss.
Using Groups with Tags
For multi-step flows, you can group requests to make metrics more readable:
import { group } from "k6";
group("login_flow", () => {
# Login Request
# Product Request
});
- Groups let you aggregate metrics for multiple requests.
- Thresholds can be applied per group as well.
Applying Thresholds to Groups
Once requests are within Group, you can define Group level thresholds in options:
export const options = {
thresholds: {
"http_req_duration{name:login}": ["p(95)<400"], // Single tag
"http_req_duration{name:products,user: admin}": ["p(95)<600"], // Multi tag
'http_req_duration{group:login_flow}': ['p(95) < 1000']
http_req_failed: ["rate<0.01"],
},
};
- Along with tag level thresholds, entire group level response time should be completed within 1 second
Putting it all together
For multi-step flows, you can group requests to make metrics more readable:
import http from "k6/http";
import { sleep, check } from "k6";
export const options = {
vus: 5,
duration: "30s",
thresholds: {
"http_req_duration{name:login}": ["p(95)<400"], // Single tag
"http_req_duration{name:products,user: admin}": ["p(95)<600"], // Multi tag
'http_req_duration{group:login_flow}': ['p(95) < 1000']
http_req_failed: ["rate<0.01"],
},
};
export default function () {
const commonHeaders = {
"Content-Type": "application/json",
"X-Client-Version": "1.0.0",
"X-Request-Source": "k6-learn-series",
};
// 1. Login and retrieve JWT
const loginPayload = JSON.stringify({
username: "testuser@example.com",
password: "supersecure",
});
group("login_flow", () => {
const loginRes = http.post(
"https://fakeloadtest.com/auth/token/login/",
loginPayload,
{ headers: commonHeaders, tags: { name: "login" } }
);
check(loginRes, {
"login successful": (r) => r.status === 200,
"token received": (r) => r.json("access") !== undefined,
});
const token = loginRes.json("access");
if (!token) return;
// Build withAuth by copying commonHeaders and adding Authorization
const withAuth = {
...commonHeaders,
Authorization: `Bearer ${token}`
};
// 2. Get Product list (protected endpoint)
let products = http.get("https://fakeloadtest.com/api/products/",
{ headers: withAuth, tags: { name: "products", user: "admin" } }
);
check(products, {
"Get Products": (r) => r.status === 200,
});
});
}
Exercise: Practice with Tags
- Add tags to all requests in your JWT SaaS products flow:
login,products,get Product,Update Product(or relevant endpoints). - Define Tag Level thresholds: login < 400 ms, products < 600 ms, get product < 200 ms.
- Define Group Level thresholds: login Group (Login api), Product group ( ge products, get single product, update product).
- Run the test and check metrics grouped by tag. Observe differences in p95 latency per endpoint.