Skip to main content

Load Testing in CircleCI: LoadFocus API Client Setup

Load Testing in CircleCI: LoadFocus API Client Setup

Key takeaways

  • The LoadFocus API Client (@loadfocus/loadfocus-api-client, npm) runs a JMeter test you have already saved in LoadFocus, waits for it, checks the result against thresholds and sets the process exit code. CircleCI fails the job on a non-zero exit.
  • Configure the client with --apikey and --teamid flags. The positional form config set apiKey <value> that older guides print does not set anything, and the run then exits 0 without testing.
  • Test the gate once with a deliberately impossible threshold. If the job does not go red, nothing is protecting your deploys.

How do I run a LoadFocus load test from CircleCI?

Install the LoadFocus API Client in a job, store your API key and team ID as CircleCI environment variables, and run loadfocus-api jmeter run-test with a --thresholds list. The command starts a saved JMeter test, polls until it finishes, evaluates the results and exits with code 1 if a threshold is missed or the run errors. CircleCI treats any non-zero exit as a failed step, so the workflow stops before deploy.

That is the whole mechanism. The rest of this page is the detail that decides whether the gate actually works: what the client needs, a config checked against CircleCI’s reference, and the traps found by reading the client’s source and running it.

What you need first

  • A JMeter test saved in your LoadFocus account. The client’s --name must match that saved test’s name (the LoadFocus docs list “verify the test name exists in your LoadFocus account” as the first fix for a failed execution). The client starts the test; it does not create it. See how to run a JMeter test in LoadFocus if you have none yet.
  • Your LoadFocus API key and team ID.
  • A CircleCI project. Add LOADFOCUS_API_KEY and LOADFOCUS_TEAM_ID under Project Settings, Environment Variables, so they never appear in .circleci/config.yml.

The client declares Node 14 or newer. I installed version 1.1.7 (published 2025-04-03, still the latest on npm on 2026-10-23) and ran it on Node 23.

A CircleCI config that fails on a missed threshold

version: 2.1

jobs:
  performance_test:
    docker:
      - image: cimg/node:24.22
    steps:
      - checkout
      - run:
          name: Install LoadFocus API Client
          command: npm install -g @loadfocus/loadfocus-api-client
      - run:
          name: Configure LoadFocus API Client
          command: |
            loadfocus-api config set --apikey "$LOADFOCUS_API_KEY" --teamid "$LOADFOCUS_TEAM_ID"
      - run:
          name: Run performance test
          no_output_timeout: 30m
          command: |
            loadfocus-api jmeter run-test \
              --name "My_Saved_JMeter_Test" \
              --thresholds "avgresponse<=200,errors==0,p95<=250" \
              --wait-timeout 1500 \
              --format json | tee performance_results.txt
      - store_artifacts:
          path: performance_results.txt
          destination: performance-test-results

workflows:
  build_test_deploy:
    jobs:
      - build_and_test
      - performance_test:
          requires:
            - build_and_test
      - deploy:
          requires:
            - performance_test
          filters:
            branches:
              only: main

I could not run this pipeline: it needs a real LoadFocus account, a saved test and a CircleCI project. What I did run is the client itself (version 1.1.7, in a scratch folder with fake credentials), and I checked the YAML keys against CircleCI’s configuration reference on 2026-10-23. build_and_test and deploy are your own jobs, which the snippet does not define.

A few choices in that config come from what I found:

  • cimg/node:24.22 replaces cimg/node:16.13, which the LoadFocus docs still print. Node 16 is long past end of life. Docker Hub listed 22, 24, 26 and lts tags for cimg/node on 2026-10-23, so check the tag list and pin a current one.
  • tee instead of > because the client prints progress lines (“Parsed threshold: …”) to standard output ahead of the JSON. A redirect leaves you a file that is not valid JSON, so treat it as a log, not as machine-readable output. With tee, the exit code that decides the build is still the client’s, because CircleCI runs run steps with pipefail by default.
  • no_output_timeout raises CircleCI’s 10 minute default for a silent command. The client prints a status line about every 10 seconds, so a normal run is not silent, but a longer test deserves the margin.
  • --wait-timeout 1500 is the real flag name (default 1800 seconds). The --waitTimeout spelling in the LoadFocus CircleCI guide is rejected by the client: it prints unknown option '--waitTimeout' (Did you mean --wait-timeout?) and exits 1.
  • store_artifacts keeps the log. CircleCI documents it as running even when an earlier step failed.

Traps that make a CI gate pass by accident

These are the reasons to read the client rather than trust a pasted snippet.

The positional config set does not work. The LoadFocus CircleCI guide and the client’s README print loadfocus-api config set apiKey $KEY. In 1.1.7 the config set command reads only the --apikey, --teamid and --url flags. I ran the positional form: it printed “Configuration updated successfully!” and then showed both values empty. A following run-test printed “Error: Missing required configuration” and exited 0. In a pipeline that is a green job with no test run. Use the flag form above, and add the deliberate-failure test below.

A malformed threshold is a warning, not an error. The parser accepts metric, one of < <= > >= = == !=, and a number, for example p95<=250. Anything else prints “Warning: Invalid threshold format” and is skipped. If every entry is skipped, the client falls back to avgresponse <= 100. So a typo does not fail the build; it silently tests something else.

errors is a count, not a percentage. The client’s own labels call it “Error Count”, so errors==0 means no failed samples at all. Thresholds are checked per label (per request name) as well as overall, which is stricter than a single overall average.

Metric names the client knows: avgresponse, p95, p99, min, max, errors and hitspersec (throughput). Response times are in milliseconds.

Exit codes. The LoadFocus docs say the command “will exit with code 1 if thresholds are not met” and the source sets exit code 1 on a failed threshold and on any error (for example an authentication failure: with a fake key I got HTTP 401 and exit 1). The one exception is the missing-configuration path above. The docs’ follow-up snippet, if [ $? -ne 0 ] after the redirect, adds nothing: CircleCI already stops at the first failing command.

Test the gate once, on purpose

Before you trust the pipeline, make it fail:

  1. Set an impossible threshold such as --thresholds "avgresponse<=1" on a branch.
  2. Push it and confirm the performance_test job goes red and deploy does not run.
  3. Remove the break. Then temporarily remove the API key variable and confirm the job still goes red (it should fail with an error, not pass).

The LoadFocus docs do not describe this check; it is the only way to know your own wiring works.

Alternatives to the client

  • Verdict API. LoadFocus can store pass/fail thresholds on the test itself (max P95, max P99, max error rate percent, min throughput) and a GET /api/v1/jmetertests/verdict?testrunname=<name>&testrunid=<id> call returns the verdict for a finished run, so any pipeline can gate on it (Pass/Fail Thresholds in the docs). You would write the curl and the parsing yourself, which this post does not demonstrate.
  • CircleCI orb. I searched CircleCI’s public orb registry through its GraphQL API on 2026-10-23 (6,420 orbs listed) and found none named for LoadFocus, so this post does not describe one.
  • Other CI systems. The LoadFocus docs have guides for GitLab CI/CD, Azure DevOps, GitHub Actions and Jenkins. For the Bitbucket version of this setup see LoadFocus API With Bitbucket Pipelines.

Practical settings

  • Keep the pipeline test short. A gate that takes an hour gets skipped. Run a short test on each merge and schedule longer soak tests separately, for example with scheduled load tests.
  • Run it after functional tests, as in the workflow above, so a broken build does not spend load-test time.
  • Run it on the branches that deploy. CircleCI documents when with pipeline.git.branch conditions at the workflow level (and when on individual steps), not on a job. The version of this page that put a when: condition block on a job was not valid configuration, so it is gone.
  • Choose thresholds from a baseline. Run the test a few times against a healthy build and set limits a little above what you see. The 200 ms and 250 ms in the example are placeholders, not recommendations.
  • Pair it with the rest of your CI/CD plan. CI/CD best practices covers the pipeline around the gate, and the 2026 guide to CI/CD load testing tools compares approaches.

Frequently Asked Questions

How do I set environment variables in CircleCI?

Open your project in CircleCI, go to Project Settings, then Environment Variables, and add LOADFOCUS_API_KEY and LOADFOCUS_TEAM_ID. Reference them in the config as $LOADFOCUS_API_KEY, never as literal values in the file.

Does the job fail when a threshold is missed?

It should: the client sets exit code 1 on a failed threshold, and CircleCI fails a step on a non-zero exit. The LoadFocus docs do not describe a test of this, so make one deliberate failure run (see above) before you rely on it.

Can I run different tests for different branches?

Yes. Give each branch’s job a different --name that matches a saved LoadFocus test, and use CircleCI branch filters on the workflow job. Keep the thresholds for the branch that deploys the strictest.

Why did my job pass without running a test?

Most likely the credentials were not set. With the positional config set apiKey form, the client reports missing configuration and still exits 0. Use --apikey and --teamid, and run the deliberate-failure test.

How do I read the results?

With --format json the client prints a JSON result with the overall pass or fail, the label-level metrics and each threshold evaluation, but progress lines come before it in the same output. Open the same run in LoadFocus for the charts.

Sources

  • LoadFocus CircleCI guide, loadfocus.com/docs/guides/jmeter-load-testing/jmeter-integration-ci-cd/circleci (read 2026-10-23)
  • LoadFocus Pass/Fail Thresholds, loadfocus.com/docs/guides/load-testing/pass-fail-thresholds (read 2026-10-23)
  • @loadfocus/loadfocus-api-client 1.1.7 on npm, README, docs and source, installed and run in a scratch folder (2026-10-23)
  • CircleCI configuration reference and variables reference, circleci.com/docs/reference (read 2026-10-23)
  • Docker Hub tag list for cimg/node (2026-10-23)
  • CircleCI orb registry GraphQL listing (2026-10-23)

Chris

Head of Content at LoadFocus

Chris leads content and oversees development across the services this blog covers. The guides and tool comparisons here come out of the same decisions that shape what ships.

Weekly tips right in your inbox.

Don’t miss out on the latest testing tips and tricks, tools and news related to software testing.

Already +20,000 members in the list.

The Load Testing Platform with AI That Explains Your Results

Load test websites and APIs from 25 cloud regions, monitor page speed and uptime, and get AI analysis that explains your results in plain English.

Cloud load testing, website speed and API monitoring in one place.

Hi there! Can I share a cool thing I'm working on with you?

A software testing newsletter that sparks joy.

Our goal is to create helpful content for software developers and testers.

If you're not into it, you can unsubscribe instantly.