No results for

Powered byAlgolia

Analyze results

In this tutorial, learn how to:

  • Apply tags to filter specific results
  • Learn about k6 metrics
  • Use jq to filter JSON results
  • Define groups to organize the test
  • Create custom metrics

Context: k6 result outputs

k6 provides many result outputs. By default, the end-of-test summary provides the aggregated results of the test metrics.

End of test summary (stdout)
checks.........................: 50.00% ✓ 4545
data_received..................: 1.3 MB 31 kB/s
data_sent......................: 81 kB 2.0 kB/s
group_duration.................: avg=6.45s min=4.01s med=6.78s max=10.15s p(90)=9.29s p(95)=9.32s
http_req_blocked...............: avg=57.62ms min=7µs med=12.25µs max=1.35s p(90)=209.41ms p(95)=763.61ms
http_req_connecting............: avg=20.51ms min=0s med=0s max=1.1s p(90)=100.76ms p(95)=173.41ms
http_req_duration..............: avg=144.56ms min=104.11ms med=110.47ms max=1.14s p(90)=203.54ms p(95)=215.95ms
{ expected_response:true }...: avg=144.56ms min=104.11ms med=110.47ms max=1.14s p(90)=203.54ms p(95)=215.95ms
http_req_failed................: 0.00% ✓ 0180
http_req_receiving.............: avg=663.96µs min=128.46µs med=759.82µs max=1.66ms p(90)=1.3ms p(95)=1.46ms
http_req_sending...............: avg=88.01µs min=43.07µs med=78.03µs max=318.81µs p(90)=133.15µs p(95)=158.3µs
http_req_tls_handshaking.......: avg=29.25ms min=0s med=0s max=458.71ms p(90)=108.31ms p(95)=222.46ms
http_req_waiting...............: avg=143.8ms min=103.5ms med=109.5ms max=1.14s p(90)=203.19ms p(95)=215.56ms
http_reqs......................: 180 4.36938/s
iteration_duration.............: avg=12.91s min=12.53s med=12.77s max=14.35s p(90)=13.36s p(95)=13.37s
iterations.....................: 45 1.092345/s
vus............................: 1 min=1 max=19
vus_max........................: 20 min=20 max=20

For simplicity to learn about k6 metric results, this tutorial uses the JSON output and jq to filter results.

For other options to analyze test results such as storage and time-series visualizations in real-time, refer to:

Write time-series results to a JSON file

To output results to a JSON file, use the --out flag.

k6 run --out json=results.json api-test.js

Then run this jq command to filter the latency results; http_req_duration metric.

jq '. | select(.type == "Point" and .metric == "http_req_duration")' results.json

k6 results have a number of built-in tags. For example, filter results to only results where the status is 200.

jq '. | select(.type == "Point" and .data.tags.status == "200")' results.json

Or calculate the aggregated value of any metric with any particular tags.

jq '. | select(.type == "Point" and .metric == "http_req_duration") | .data.value' results.json | jq -s 'add/length'

Apply custom tags

You can also apply Tags to requests or code blocks. For example, this is how you can add a tags to the request params.

const params = {
headers: {
"Content-Type": "application/json",
tags: {
"my-custom-tag": "auth-api",

Create a new script named "tagged-login.js", and add a custom tag to it.

import http from "k6/http";
export default function () {
const url = "";
const payload = JSON.stringify({
username: "test_case",
password: "1234",
const params = {
headers: {
"Content-Type": "application/json",
//apply tags
tags: {
"my-custom-tag": "auth-api"
//Login with tags`${url}/auth/basic/login`, payload, params);

Run the test:

k6 run --out json=results.json tagged-login.js

Filter the results for this custom tag:

jq '. | select(.type == "Point" and .metric == "http_req_duration" and .data.tags."my-custom-tag" == "auth-api")' results.json

Organize requests in groups

You can also organize your test logic into Groups. Test logic inside a group tags all requests and metrics within its block. Groups can help you organize the test as a series of logical transactions or blocks.

Context: a new test to group test logic

Results filtering isn't very meaningful in a test that makes one request. And the API test script is getting long. To learn more about how to compare results and other k6 APIs, write a test for the following situation:

A dummy example: your development team wants to evaluate the performance of two user-facing flows.

  • visit an endpoint, then another one
    • A GET request to
    • A GET to
  • play the coinflip game:
    • A POST request to with the query param bet=heads
    • Another POST to with the query param bet=tails

Can you figure out how to script the requests? If not, use the following script.

script example

Since this example simulates a human user rather than an API call, it has a sleep between each request. Run with k6 run multiple-flows.js.

1import http from "k6/http";
2import { group, sleep } from "k6";
4//set URL as variable
5const baseUrl = "";
7export default function () {
8 // visit contacts
9 http.get(`${baseUrl}/contacts.php`);
10 sleep(1);
11 // return to the home page
12 http.get(`${baseUrl}/`);
13 sleep(1);
15 //play coinflip game
16 http.get(`${baseUrl}/flip_coin.php?bet=heads`);
17 sleep(1);
18 http.get(`${baseUrl}/flip_coin.php?bet=tails`);
19 sleep(1);

Add Group functions

Wrap the two endpoints in different groups. Name one group Contacts flow and another Coinflip game.

1//import necessary modules
2import http from "k6/http";
3import { group, sleep } from "k6";
5//set baseURL
6const baseUrl = "";
8export default function () {
10 // visit some endpoints in one group
11 group("Contacts flow", function () {
12 http.get(`${baseUrl}/contacts.php`);
13 sleep(1);
14 // return to the home page
15 http.get(`${baseUrl}/`);
16 sleep(1);
17 });
19 // Coinflip players in another group
20 group("Coinflip game", function () {
21 http.get(`${baseUrl}/flip_coin.php?bet=heads`);
22 sleep(1);
23 http.get(`${baseUrl}/flip_coin.php?bet=tails`);
24 sleep(1);
25 });

Run and filter

Inspect the results for only the Coinflip game group. To do so:

  1. Save the preceding script as multiple-flows.js.

  2. Run the script with the command:

    k6 run multiple-flows.js --out json=results.json --iterations 10
  3. Inspect the results with jq. Group names have a :: prefix.

    jq '. | select( == "::Coinflip game")' results.json

Add a custom metric

As you have seen in the output, all k6 tests emit metrics. However, if the built-in metrics aren't enough, you can create custom metrics. A common use case is to collect metrics of a particular scope of your test.

As an example, create a metric that collects latency results for each group:

  1. Import Trend from the k6 metrics module.
  2. Create two duration trend metric functions.
  3. In each group, add the duration time to the trend for requests to contacts and the coin_flip endpoints.
1//import necessary modules
2import http from "k6/http";
3import { group, sleep } from "k6";
4import { Trend } from "k6/metrics";
6//set baseURL
7const baseUrl = "";
9// Create custom trend metrics
10const contactsLatency = new Trend("contacts_duration");
11const coinflipLatency = new Trend("coinflip_duration");
13export default function () {
14 // Put visits to contact page in one group
15 let res;
16 group("Contacts flow", function () {
17 // save response as variable
18 res = http.get(`${baseUrl}/contacts.php`);
19 // add duration property to metric
20 contactsLatency.add(res.timings.duration);
21 sleep(1);
23 res = http.get(`${baseUrl}/`);
24 // add duration property to metric
25 contactsLatency.add(res.timings.duration);
26 sleep(1);
27 });
29 // Coinflip players in another group
31 group("Coinflip game", function () {
32 // save response as variable
33 let res = http.get(`${baseUrl}/flip_coin.php?bet=heads`);
34 // add duration property to metric
35 coinflipLatency.add(res.timings.duration);
36 sleep(1);
38 res = http.get(`${baseUrl}/flip_coin.php?bet=tails`);
39 // add duration property to metric
40 coinflipLatency.add(res.timings.duration);
41 sleep(1);
42 });

Run the test with small number of iterations and output the results to results.json.

k6 run multiple-flows.js --out json=results.json --iterations 10

Look for the custom trend metrics in the end-of-test console summary.

coinflip_duration..............: avg=119.6438 min=116.481 med=118.4755 max=135.498 p(90)=121.8459 p(95)=123.89565
contacts_duration..............: avg=125.76985 min=116.973 med=120.6735 max=200.507 p(90)=127.9271 p(95)=153.87245

You can also query custom metric results from the JSON results. For example, to get the aggregated results as.

jq '. | select(.type == "Point" and .metric == "coinflip_duration") | .data.value' results.json | jq -s 'add/length'

Next steps

In this tutorial, you looked at granular output and filtered by built-in and custom tags. Then you made a new script with groups. Finally, you added a new metric for each group. A next step would be to create a Custom end-of-test summary or to stream the results to a database.

For ongoing operations, you can modularize your logic and configuration. That's the subject of the next step of this tutorial.