View all services
Talk to QA Advisor
Browse the Knowledge Hub211 resources
Tools Library · Review and guide

Karate review: API testing tutorial, pricing and setup

Karate is an open source test framework for APIs that uses a Gherkin-style language, so HTTP calls, JSON assertions and data setup are written without Java. It also bundles mock servers, Gatling-based performance testing and browser automation. Version 2, a ground-up rewrite on Java 21, was released on 26 March 2026; the current release is 2.1.3.

QAble has evaluated this tool and works alongside it. The factual sections are complete; our view is bounded to what we have actually seen rather than a long-term verdict.

last reviewed
13 October 2026
version covered
Karate 2
licence
Open source

Reviewed by Viral Patel

Co-Founder, QAbleLast reviewed 13 October 2026

At a glance

Karate at a glance

Official site
Vendor
Karate Labs
Category
API testing, BDD frameworks, Performance testing
Licence
Open source (MIT, with commercial Karate Labs products)
Platforms
JVM
Languages
Karate DSL, JavaScript
Integrates with
JUnit, Maven, Gatling, Gradle
First released
2017
Version reviewed
Karate 2

Verdict

Our verdict on Karate

Strengths

  • API tests read as plain steps, so testers without Java can write and review them
  • match with markers such as #string and #uuid validates whole payloads in one line
  • Parallel execution at feature, scenario and example level is built in, on Java 21 virtual threads
  • Mocks are written in the same language, and existing features run as Gatling load scenarios
  • Runs through Maven or Gradle, or as a standalone CLI with no build tool
  • Core framework is free under the MIT licence

Weaknesses

  • A custom language: complex logic moves into embedded JavaScript, which is harder to debug than Java
  • Version 2 needs Java 21 and silently ignores the v1 @parallel=false tag
  • Kafka, gRPC and WebSocket testing, and the richer IDE plugins, are commercial products
  • Smaller community than REST Assured or Postman, and many answers online describe v1

Our take

Karate fits teams that want API tests in a repository, reviewed like code, but whose testers are not Java developers. Its match syntax and fuzzy markers make JSON assertions shorter than in any code library, mocks are written in the same language, and existing features can run as Gatling load tests. QAble has evaluated it rather than maintained a long-running suite on it, so treat this as a bounded take. Two cautions. The Gherkin-like syntax is readability, not BDD: nothing about it creates shared discovery with the business unless the team does that work. And version 2 is a full rewrite: most v1 features run unchanged, but @parallel=false is silently ignored, JUnit XML is now opt-in and Java 21 is required, so upgrade on a branch and compare reports before switching CI.

We have evaluated this tool rather than maintained a long-running suite on it, so this is a bounded view rather than a long-term verdict. The rest of this page is factual.

How it works

How Karate works

Feature files interpreted on the JVM

A Karate test is a .feature file of Scenarios, each a list of steps such as url, path, request, method and match. Karate parses the file itself rather than mapping steps to Java glue code as Cucumber does, so there is no step definition layer to write. Variables, JSON and XML are first-class: a step can declare a JSON literal, embed expressions with #(), call another feature, or run JavaScript. The interpreter, HTTP client and reports all run on the JVM, so Java is needed at run time even though tests contain none, and Java classes can be called when the DSL runs out.

Version 2: a rewrite on Java 21

Karate 2.0.0, released on 26 March 2026, replaced the engine. GraalJS gave way to karate-js, an embedded JavaScript engine designed to be thread-safe, and parallel execution moved to Java 21 virtual threads. The HTTP client moved to Apache HttpClient 5.6, the mock server was rebuilt on Netty, Gatling integration was reimplemented in Java without Scala, and the HTML reports were redesigned. Backward compatibility shims keep the v1 com.intuit.karate Runner, Results and MockServer classes working, so the migration guide says most projects only need a dependency and Java version change. The exceptions are in parallel tags, reporting and logging.

match and fuzzy markers

Assertions centre on match. A single match compares a whole JSON or XML document against an expected shape, with markers such as #string, #uuid, #regex, #notnull, #present and #ignore standing in for values that vary, and a double hash making a field optional. match each applies a shape to every array element, and contains and within check subsets and ranges. A failed match in version 2 reports every mismatched path with actual and expected values. This is why Karate tests are short: one match replaces a dozen field assertions.

Configuration through karate-config.js

Before each scenario, Karate runs karate-config.js, a JavaScript function that returns variables available to every feature. It reads karate.env, set with -Dkarate.env in Maven or -e on the CLI, to choose base URLs and credentials per environment, and can call configure for timeouts, headers, logging or authentication. Version 2 adds a declarative configure auth for Basic, Bearer, OAuth2 with automatic token refresh, and NTLM. Because the config runs per scenario, expensive setup such as fetching a token belongs in karate.callSingle or callonce, not in plain config code.

Strengths

What it does well

Readable API tests without a language barrier

A tester who understands HTTP and JSON can read and write Karate scenarios within days. Requests, chaining and assertions need no classes, imports or build knowledge, which widens who can contribute to a code-reviewed API suite compared with a Java or JavaScript library.

Data-driven and reusable scenarios

Scenario Outline with Examples tables runs a scenario once per row, and each row runs in parallel. call and callonce reuse whole features, for example a login feature returning a token, with arguments passed as JSON. Dynamic scenarios can generate examples from a function or a file.

Mocks from the same language

Karate’s mock server serves responses defined in feature files or JavaScript handlers, with request matching and delays. Teams use it to stand in for a dependency during integration tests or to give consumers a working stub before the provider exists, without adding WireMock or another tool.

Performance tests that reuse functional scenarios

The Gatling integration runs existing features as load, using karateProtocol and karateFeature in a Java simulation. Assertions and request chaining come along for free, so a performance smoke test needs little new code. In version 2 Gatling session values must be read with the __gatling prefix.

One tool across API, UI and SOAP

Beyond REST and GraphQL, Karate sends SOAP requests with XML match support, and its browser automation drives Chrome and Edge through the DevTools Protocol, and Chrome, Firefox, Safari and Edge through W3C WebDriver. For teams that want one framework and one report format across layers, that breadth is unusual.

Pricing

Karate pricing and licensing

The Karate framework is open source under the MIT licence and costs nothing, including API testing, mocks, Gatling integration, UI automation and CI use. Karate Labs, the company behind it, sells per-user products around the core: IDE Plus and Pro plans with richer IntelliJ and VS Code plugins and Xplorer Premium, and Karate Enterprise on a custom annual licence with async protocol testing, Karate Agent and commercial support.

  • Licence: MIT for the framework, stated in the repository’s LICENSE file. Nothing in the core runner is held back.
  • Free: the framework, CI runs, the standalone CLI and the free tier of the Xplorer desktop client.
  • Paid per user: IDE Plus and Pro, priced per user, add IDE debugging and autocomplete, Xplorer Premium and, in Pro, a development-time licence for Kafka, gRPC and WebSocket testing.
  • Enterprise: custom pricing for runtime async protocol licences in CI, Karate Agent, API coverage and governance features, floating licences and an SLA.
  • Hidden costs: Java 21 on every build agent, and the time to migrate v1 suites, scrapers and dashboards to v2 reports.

Checked against the vendor’s own pages on 13 October 2026. Pricing changes; confirm on the official site before buying.

Getting started

Karate tutorial: getting started

Setup, step by step

  1. Install Java 21 or later, which Karate 2 requires.
  2. Either install the standalone CLI, or add karate-junit6 and junit-jupiter to a Maven or Gradle project.
  3. Create karate-config.js returning a baseUrl, switched on karate.env.
  4. Write a feature file under src/test/java next to its runner, or anywhere for the CLI.
  5. Run it with karate users.feature, or with mvn test through a JUnit runner class.
  6. Open target/karate-reports/karate-summary.html to see each request and response.

Install

# standalone CLI on macOS or Linux
curl -fsSL https://karate.sh/install.sh | sh
karate users.feature

# or in a Maven project: io.karatelabs:karate-junit6:2.1.3 plus
# org.junit.jupiter:junit-jupiter, both with test scope

A first example

Feature: Orders API

  Background:
    * url baseUrl

  Scenario: create an order and read it back
    Given path 'orders'
    And request { sku: 'ABC-1', quantity: 2 }
    When method post
    Then status 201
    # Markers validate shape where values vary
    And match response == { id: '#uuid', status: 'PENDING', lines: '#[1]' }
    * def orderId = response.id

    Given path 'orders', orderId
    When method get
    Then status 200
    And match response.lines[0] contains { sku: 'ABC-1', quantity: 2 }

What trips people up first

The right-hand side of a step is not always JavaScript. Anything starting with { or [ is parsed as Karate’s relaxed JSON, where a bare identifier on the value side is read as a string, so { id: orderId } sends the text orderId rather than the variable. Use an embedded expression, { id: "#(orderId)" }, or wrap the literal in parentheses to force JavaScript, ({ id: orderId }). The same rule applies to arguments of call. The second hurdle is the Java version: Karate 2 fails on anything older than Java 21, so check the JDK on every CI agent before blaming the tests.

In practice

Using Karate in practice

Project layout and environment config

Karate’s own recommendation is to keep feature files next to the Java runner under src/test/java, grouped by domain, such as orders and accounts, rather than in a separate resources tree. Put karate-config.js at the classpath root and keep environment differences there: base URLs and non-secret settings per karate.env, secrets from environment variables or system properties. Put shared flows, such as obtaining a token, in their own features and call them with callonce so they run once per feature rather than once per scenario. Tag scenarios with @smoke, @regression or @ignore from the start, because tags are how the runner and CI select subsets.

// src/test/java/karate-config.js
function fn() {
  var env = karate.env || 'dev'
  var config = { baseUrl: 'http://localhost:8080' }
  if (env === 'staging') {
    config.baseUrl = 'https://staging.example.com'
  }
  // Secrets come from the CI environment, never from the repository
  config.apiToken = karate.sysenv('API_TOKEN')
  karate.configure('headers', { Authorization: 'Bearer ' + config.apiToken })
  return config
}

Running in parallel with the Runner API

For CI, run everything through a single JUnit test that calls the parallel runner rather than through one runner class per feature. Runner.path selects features, tags filters them, and parallel sets the thread count and must be the last call. Version 2 produces only HTML reports by default, so turn on JUnit XML explicitly if your CI publishes test results. Scenarios must be independent: they run in any order and on different threads, so a scenario that relies on data created by another will fail intermittently. Where scenarios genuinely share a resource, serialise just those with @lock=name rather than slowing the whole suite.

// src/test/java/ApiSuiteTest.java
import static org.junit.jupiter.api.Assertions.assertEquals;

import io.karatelabs.core.Runner;
import io.karatelabs.core.SuiteResult;
import org.junit.jupiter.api.Test;

class ApiSuiteTest {
  @Test
  void runAll() {
    SuiteResult result = Runner.path("classpath:api")
        .tags("~@ignore")
        .outputJunitXml(true) // opt-in since v2
        .parallel(8);         // must be called last
    assertEquals(0, result.getScenarioFailedCount(), String.join("\n", result.getErrors()));
  }
}

Running Karate in GitHub Actions

A Karate suite in a Maven project runs with a normal build: set up Java 21, run the suite test, and upload target/karate-reports so the HTML report, with every request and response, is one click from a failed job. Pass the environment with -Dkarate.env and secrets as environment variables read by karate.sysenv. Karate’s own CI guide also recommends scanning published reports for leaked tokens, since the HTML report records headers and bodies; configure logging masks for Authorization headers before reports leave the build.

# .github/workflows/karate.yml
name: karate
on: [push, pull_request]
jobs:
  api:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-java@v6
        with:
          distribution: temurin
          java-version: '21'
          cache: maven
      - name: Run Karate suite
        run: mvn -B test -Dtest=ApiSuiteTest -Dkarate.env=staging
        env:
          API_TOKEN: ${{ secrets.STAGING_API_TOKEN }}
      - uses: actions/upload-artifact@v7
        if: always()
        with:
          name: karate-reports
          path: target/karate-reports/

Moving a v1 suite to v2

Work through the migration guide on a branch. Swap karate-junit5 for karate-junit6, add junit-jupiter explicitly because v2 no longer bundles it, move the build to Java 21 and Surefire 3.2.5 or later, and run the suite. Then search for the changes that do not fail loudly. @parallel=false is ignored without a warning, so replace it with @lock. karate-summary.json and the per-feature JSON files are gone; scrapers should read the karate-events.jsonl stream. Logging options such as logPrettyRequest are now no-ops under configure logging. karate-robot is not part of v2, and image comparison moved to the karate-image extension. Compare a v1 and v2 report for the same commit before switching CI.

Keeping scenarios maintainable

Karate suites degrade in a recognisable way: scenarios grow long JavaScript blocks, called features take many arguments, and nobody can tell what a failure means. Keep JavaScript in small named functions, defined once and read in, or move real logic into a Java helper called through Java.type. Prefer one match against a full expected shape over many single-field checks, and store expected payloads as JSON files when they are long. Add a Gherkin comment above important match steps: in version 2 that comment becomes the failure label in the report, which makes CI failures readable to people who did not write the test.

Pitfalls

Common pitfalls

Relying on @parallel=false after upgrading to v2

Why it happens: Version 2 dropped the tag and silently ignores it, with no warning or error, so features that must run sequentially start running in parallel and fail intermittently.

The fix: Replace it with @lock=name on the Feature line, or @lock=* where the feature must run alone, and search the repository for any remaining @parallel=false tags.

CI losing test results after the upgrade

Why it happens: v2 writes only HTML reports by default. JUnit XML and Cucumber JSON are opt-in, and the old karate-summary.json no longer exists.

The fix: Call outputJunitXml(true) or outputCucumberJson(true) on the runner, or pass -f junit:xml on the CLI, and point scrapers at karate-events.jsonl.

Variables sent as literal strings in JSON

Why it happens: A right-hand side starting with { or [ is Karate JSON, not JavaScript, so a bare identifier such as orderId becomes the string orderId.

The fix: Use embedded expressions such as #(orderId), or wrap the literal in parentheses to evaluate it as JavaScript.

Tests that pass alone and fail in the parallel run

Why it happens: Scenarios share an order, user or account created elsewhere, or depend on Background variables mutated by another scenario. In parallel the order is not guaranteed.

The fix: Create the data each scenario needs inside it, or through callonce per feature, and use @lock only for genuinely shared resources.

Secrets leaking into published HTML reports

Why it happens: Reports include full request and response headers and bodies by default, so tokens and passwords end up in CI artefacts and published pages.

The fix: Use configure logging with a mask for headers such as Authorization and JSON paths such as $.password, and scan report artefacts before publishing them.

Expecting Kafka, gRPC or WebSocket testing in the open source core

Why it happens: Karate’s pricing page lists async protocol testing as a commercial module, available in the Pro and Enterprise offerings.

The fix: Budget for the commercial licence, or test those protocols with another tool and keep Karate for HTTP, SOAP and GraphQL.

Compared

How Karate compares

ToolTest languageAssertion styleMocks built inLoad testingLicence
KarateKarate DSL with embedded JavaScriptmatch with fuzzy markersYes, feature or JavaScript handlersReuses features through GatlingMIT, commercial add-ons
REST AssuredJava, Kotlin, Groovy, ScalaHamcrest matchers on GPathNo, use WireMock or similarNoApache 2.0
PostmanJavaScript in the Postman sandboxChai via pm.expectYes, hosted or local mock serversPerformance runs, cloud runs billedProprietary, freemium
CucumberGherkin plus step definitions in codeWhatever the step code usesNoNoMIT

FAQ

Frequently asked questions

Is Karate free?

The Karate framework is free and open source under the MIT licence, including API testing, mocks, Gatling integration, browser automation and CI use. Karate Labs sells optional products: per-user IDE Plus and Pro plans with advanced IntelliJ and VS Code plugins and Xplorer Premium, and Karate Enterprise with Kafka, gRPC and WebSocket testing in CI, Karate Agent and commercial support. You can run a full API suite without paying anything.

What changed in Karate 2?

Karate 2 is a ground-up rewrite released on 26 March 2026. It requires Java 21, replaces GraalJS with its own karate-js engine, uses virtual threads for parallel runs, moves JUnit integration to karate-junit6 and redesigns reports, with JUnit XML now opt-in. @parallel=false is replaced by @lock, logging options are consolidated under configure logging, and karate-robot is not included. Compatibility shims keep most v1 code working.

Do I need to know Java to use Karate?

Not to write tests. Scenarios are written in Karate’s own language, with JavaScript for any logic, and the standalone CLI runs features without Maven or Gradle. Java is needed at run time, version 21 for Karate 2, and someone on the team should be comfortable with a Maven or Gradle build if the suite runs through JUnit in CI. Java classes can be called from features when you need them.

Is Karate a BDD tool?

It uses Gherkin keywords, but it is not BDD in the Cucumber sense. Karate steps are executable HTTP and JSON instructions interpreted directly, not business-language steps mapped to glue code, so feature files describe API calls rather than behaviour agreed with stakeholders. Teams that want BDD collaboration should use Cucumber or SpecFlow-style tooling for that conversation and can still use Karate for the API layer.

Karate or REST Assured?

Choose Karate when testers are not Java developers, when you want compact whole-payload assertions, or when mocks and performance reuse in one tool matter. Choose REST Assured when the team writes Java or Kotlin, wants to share model classes with the service and prefers ordinary code with full IDE refactoring. Both run on the JVM and fit Maven and Gradle builds.

Can Karate run tests in parallel?

Yes, and it is built in. The parallel runner runs features, scenarios and Scenario Outline examples concurrently, and Karate 2 uses Java 21 virtual threads so large thread counts are cheap. Scenarios must be independent of each other. Use @lock=name to serialise scenarios that share a resource, @lock=* for a scenario that must run alone, and abortSuiteOnFailure when a fast failing exit code matters more than a full report.

Alternatives

Karate alternatives worth weighing

Resources

Where to go next

Keep going

Prepare, or get it done

Ready

Picking the wrong tool costs more than picking late.

QAble advises on toolchain decisions and then implements them, with engineers who have run these tools on real delivery. Start with a free QA audit.

Talk to QA Advisor