Q38 of 40 · Karate

How would you build a custom Karate plugin or extend the DSL? What's the extension boundary?

KarateSeniorkarateextensibilitypluginsruntime-hookadvanced

Short answer

Short answer: Karate exposes HttpClientFactory to replace the HTTP client entirely and PerfEvent for custom metrics hooks. For custom logic, write a Java class and call it via Java.type() or karate.call(). New Gherkin keywords are not supported — the extension boundary is Java and JavaScript called from within feature files, not parser-level DSL changes.

Detail

Karate's extension points, from easiest to most advanced:

1. JavaScript helpers (easiest): write utility functions in a .js file, import with read(), and call from any scenario. No Java required.

2. Java class via Java.type(): any Java class on the classpath is callable:

* def CryptoHelper = Java.type('com.example.test.CryptoHelper')
* def signature    = CryptoHelper.hmacSign(payload, secret)

3. Custom RuntimeHook: implement com.intuit.karate.RuntimeHook to hook into beforeScenario, afterScenario, beforeStep, afterStep — useful for custom reporting, performance tracking, or injecting variables at runtime:

public class MyHook implements RuntimeHook {
    @Override public boolean beforeScenario(ScenarioRuntime sr) {
        sr.engine.setVariable("runId", UUID.randomUUID().toString());
        return true;
    }
}

Register in karate-config.js: karate.configure('hooks', [new MyHook()])

4. Custom HttpClient (most advanced): implement HttpClientFactory to replace the HTTP transport layer entirely — useful for adding custom signing, HTTP/3, or a non-standard transport.

What is NOT possible: adding new Gherkin keywords (Given myCustomStep), changing the DSL syntax, or modifying the match semantics. Karate's parser is not extensible at the keyword level.

// EXAMPLE

HmacSigningHook.java

// Custom RuntimeHook that adds HMAC signature to every request
public class HmacSigningHook implements RuntimeHook {
    private final String secretKey;

    public HmacSigningHook(String secretKey) {
        this.secretKey = secretKey;
    }

    @Override
    public boolean beforeRequest(HttpRequest request, ScenarioRuntime sr) {
        String body = request.getBodyAsString() != null
            ? request.getBodyAsString() : "";
        String timestamp = String.valueOf(System.currentTimeMillis());
        String signature = HmacUtils.sign(timestamp + body, secretKey);

        request.setHeader("X-Timestamp", timestamp);
        request.setHeader("X-Signature",  signature);
        return true;  // proceed with the request
    }
}

// Register in karate-config.js:
// var HmacSigningHook = Java.type('com.example.test.HmacSigningHook');
// karate.configure('hooks', [new HmacSigningHook(java.lang.System.getenv('HMAC_SECRET'))]);

// WHAT INTERVIEWERS LOOK FOR

Understanding the four extension layers (JS helpers, Java.type, RuntimeHook, HttpClientFactory) and the hard boundary (no new DSL keywords). RuntimeHook for request signing is a concrete, practical use case. Knowing the limit prevents over-engineering.

// COMMON PITFALL

Trying to add custom step keywords by modifying Karate source code (forking the library). The correct approach is RuntimeHook or Java.type — custom keywords require maintaining a Karate fork, which creates a long-term maintenance burden.