Skip to content

k6 Custom Metric Not Recording Values Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about k6 custom metric not recording values fix. We cover key concepts, practical examples, and best practices.

Your k6 custom metric shows zero or no data at the end of the test — the metric is declared but add() is never called, the metric is used outside the default function, or the metric type does not match the data pattern.

The Problem

import http from 'k6/http';
import { Trend } from 'k6/metrics';

const responseSize = new Trend('response_size');

// WRONG: metric added outside the default function
const res = http.get('https://api.example.com');
responseSize.add(res.body.length);

export default function () {
  // No metric calls here
}
     response_size.............: 0     min=0  max=0

The add() call runs at module load time, not during VU iterations. Metrics must be recorded inside the default function.

Step-by-Step Fix

1. Record metrics inside the default function

import http from 'k6/http';
import { Trend } from 'k6/metrics';

const responseSize = new Trend('response_size');

export default function () {
  const res = http.get('https://api.example.com');
  responseSize.add(res.body.length);
}

2. Use Counter metrics for counts

import http from 'k6/http';
import { Counter } from 'k6/metrics';

const apiCalls = new Counter('api_calls');
const errors = new Counter('api_errors');

export default function () {
  const res = http.get('https://api.example.com');
  apiCalls.add(1);

  if (res.status !== 200) {
    errors.add(1);
  }
}

3. Use Gauge metrics for point-in-time values

import http from 'k6/http';
import { Gauge } from 'k6/metrics';

const activeConnections = new Gauge('active_connections');

export default function () {
  const res = http.get('https://api.example.com');
  activeConnections.add(42);  // Last value wins
}

4. Use Rate metrics for pass/fail ratios

import http from 'k6/http';
import { Rate } from 'k6/metrics';

const successRate = new Rate('success_rate');

export default function () {
  const res = http.get('https://api.example.com');
  successRate.add(res.status === 200);
}

5. Tag custom metrics for granularity

import http from 'k6/http';
import { Trend } from 'k6/metrics';

const apiLatency = new Trend('api_latency');

export const options = {
  thresholds: {
    'api_latency{endpoint:users}': ['p(95)<1000'],
    'api_latency{endpoint:orders}': ['p(95)<3000'],
  },
};

export default function () {
  const users = http.get('https://api.example.com/users');
  apiLatency.add(users.timings.duration, { endpoint: 'users' });

  const orders = http.get('https://api.example.com/orders');
  apiLatency.add(orders.timings.duration, { endpoint: 'orders' });
}

Expected output:

     api_calls.................: 5000    500/s
     api_errors................: 10      1/s
     success_rate..............: 99.80%  ✓ 4990  ✗ 10
     api_latency...............: avg=145ms  p(95)=320ms

Prevention Tips

  • Always call .add() inside the default function, not at module level
  • Match metric type to data: Trend for durations, Counter for counts, Gauge for current values, Rate for ratios
  • Use tags for metric granularity without creating separate metrics
  • Set thresholds on custom metrics for CI pass/fail
  • Verify metric output with a short test before full run

Common Mistakes with custom metrics

  1. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  2. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  3. Using head and tail instead of pattern matching, causing runtime errors on empty lists

These mistakes appear frequently in real-world K6 code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Can I use custom metrics in thresholds?

Yes. Custom Trend, Counter, Gauge, and Rate metrics can all be used in thresholds. The same aggregation functions apply: avg, p(95), rate, count, etc.

What's the difference between Trend and Rate?

Trend records individual values and computes statistics (avg, min, max, p95). Rate tracks the ratio of non-zero adds to total adds — use it for pass/fail tracking (e.g., success_rate.add(res.status === 200)).

Do custom metrics affect performance?

Yes, every add() call consumes CPU and memory. For high-throughput tests (10,000+ requests/second), minimize custom metric calls or batch them. Use k6's built-in metrics where possible.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro