npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

har-to-slo

v0.1.0

Published

Turn HAR timing data into k6 SLO baselines — your recordings already know your p95

Downloads

336

Readme

📐 har-to-slo

Your HAR file already knows your p95. You just haven't asked it yet.

Every time you record a HAR — from Playwright, Chrome DevTools, an API gateway export, or a browser session — you're capturing real latency measurements for every route in your app. har-to-slo reads those measurements, computes p95 baselines per route, and outputs a ready-to-use k6 thresholds {} block. Stop inventing SLO numbers. Derive them.

Not a HAR-to-k6-script converter. grafana/har-to-k6 replays traffic. har-to-slo reads the timings in that same file and turns them into statistically grounded SLO baselines. They complement each other — use both.

CI CodeQL npm version License MIT Agent Skill

har-to-slo running against a real 48-entry HAR — 6 routes collapsed, p95 baselines with 1.5× multiplier

☝️ Real output from a 48-entry HAR. Six routes, all HTTP methods, zero configuration.


The problem it solves

When you add a k6 thresholds {} block, you need a number:

"http_req_duration{url:/api/orders}": ["p(95)<???"],

Where does that number come from? Usually: a guess, a round number, or copied from another service. har-to-slo answers that question with measured data from your own traffic.


Install

# No install needed — run with npx
npx har-to-slo --input recording.har

Usage

# Basic — outputs k6 thresholds block to stdout
npx har-to-slo --input recording.har

# Tighter SLOs (1.2× p95 instead of default 1.5×)
npx har-to-slo --input recording.har --multiplier 1.2

# JSON — for CI pipelines and tooling integrations
npx har-to-slo --input recording.har --format json

# Write directly into your k6 script file
npx har-to-slo --input recording.har --output k6/thresholds.js

# With LLM rationale for each threshold (requires ANTHROPIC_API_KEY)
npx har-to-slo --input recording.har --explain

Supported sources

| Source | Command | What it reads | |---|---|---| | har (default) | har-to-slo --input recording.har | HAR file timing data | | k6 | har-to-slo --source k6 --input summary.json | k6 --summary-export JSON | | logs | har-to-slo --source logs --input nginx.log | nginx / ALB / NDJSON access logs | | otel | har-to-slo --source otel --input traces.jsonl | OpenTelemetry trace JSONL export | | prometheus | har-to-slo --source prometheus --url http://prom:9090 --query http_request_duration_seconds | Prometheus / Mimir HTTP API |

Using with the Grafana stack

# From a k6 load test run
k6 run --summary-export summary.json load-test.js
har-to-slo --source k6 --input summary.json

# From Grafana Mimir (or any Prometheus)
har-to-slo --source prometheus \
  --url http://mimir.internal:9090 \
  --query http_request_duration_seconds \
  --range 30d

# From Grafana Tempo trace export (OTEL JSONL)
har-to-slo --source otel --input tempo-export.jsonl

How it works

HAR file
  └─ entry.time per request (real latency in ms)
       └─ collapse URLs: /users/123 → /users/{id}
            └─ group by METHOD + template
                 └─ trim top 5% outliers
                      └─ compute p95 per group
                           └─ threshold = Math.round(p95 × multiplier)
                                └─ emit k6 thresholds {} block

A HAR entry's .time field is the total wall-clock duration of that request as observed by the client. This is the same number your users experience. It's the right number for an SLO.


Output example

Given a HAR with requests to 6 routes:

// Auto-generated by har-to-slo
// https://github.com/aks-builds/har-to-slo

export const options = {
  thresholds: {
    // GET /api/v1/users/{id} — p95 baseline: 142ms (n=8, ×1.5)
    "http_req_duration{scenario:GET_/api/v1/users/_id_}": ["p(95)<213"],
    // GET /api/v1/products — p95 baseline: 250ms (n=8, ×1.5)
    "http_req_duration{scenario:GET_/api/v1/products}": ["p(95)<375"],
    // POST /api/v1/orders — p95 baseline: 610ms (n=8, ×1.5)
    "http_req_duration{scenario:POST_/api/v1/orders}": ["p(95)<915"],
  },
};

Using alongside grafana/har-to-k6

These tools do different things and work together:

# Step 1 — generate a k6 load test script from your HAR recording
npx har-to-k6 recording.har -o load-test.js

# Step 2 — generate statistically grounded thresholds for that script
npx har-to-slo --input recording.har --output thresholds.js

# Step 3 — merge thresholds.js into load-test.js

har-to-k6 asks: "what requests should my load test replay?" har-to-slo asks: "what latency should I fail the load test at?"


Options

| Flag | Default | Description | |---|---|---| | --input, -i | (required) | Path to HAR file | | --multiplier, -m | 1.5 | Threshold = p95 × multiplier | | --format, -f | js | Output format: js or json | | --output, -o | stdout | Write to file instead of stdout | | --explain, -e | off | Annotate with Claude Haiku rationale (needs ANTHROPIC_API_KEY) |


E2E test results

| Dataset | Entries | Routes | Status | |---|---|---|---| | Small | 5 | 3 | ✅ | | Medium | 48 | 6 | ✅ | | Large | 500 | 10 (with UUIDs) | ✅ |


Claude Code Skill

A bundled Claude Code skill lets AI agents call har-to-slo during PR review to check whether load test thresholds are grounded in real data or invented.


License

MIT © aks-builds