Java SDK
Read Intempt feature flags, experiments and personalizations by key from a JVM server.
Java SDK
Reads decisions. It does not send events.
Every other Intempt SDK on this list captures events; this one asks Intempt what to serve and
nothing else. Its whole public surface is eight methods on IntemptClient, and all eight are flag
reads. To send events from the JVM, post to the REST API.
It holds no per-user state: every call takes its identifier explicitly, so one client instance is shared across every request and every thread.
Not published yet. intempt-java has no tag, no GitHub release, and nothing under
com.intempt on Maven Central. The coordinates below are what the POM declares, not something you
can resolve today — until an artifact is published, build the repository yourself and install it
into your local repository.
Requirements
| Java | 17 or newer |
| Runtime dependencies | none |
| Thread safety | one client, shared |
No runtime dependencies is deliberate. This SDK is dropped into applications that already pin a
JSON library, and a transitive version conflict is a bug that surfaces in someone else's release
build rather than in ours. java.net.http plus a small reader cover what it needs.
Installation
<dependency>
<groupId>com.intempt</groupId>
<artifactId>intempt-java</artifactId>
<version>0.1.0</version>
</dependency>Setup
| value | where it comes from | required |
|---|---|---|
org | your organization name in the console URL | yes |
project | your project name in the console URL | yes |
sourceId | the source you are sending as | yes |
apiKey | a server key from the console | yes |
host | override the API host | no |
timeout | per-request timeout | no |
IntemptConfig config = IntemptConfig.builder()
.org("acme")
.project("web")
.sourceId("42")
.apiKey(System.getenv("INTEMPT_API_KEY"))
.timeout(Duration.ofMillis(800))
.build();
try (IntemptClient client = new IntemptClient(config)) {
// ...
}The evaluation endpoint requires a server credential. A public key holds users and accounts and nothing else, and the response describes how every experience in the project targets, so a public key is refused there.
Identity
FlagContext carries who is being evaluated. profileId is the anonymous or device identifier;
passing the same value before and after someone signs in is what keeps their assignment stable
across the transition.
FlagContext.ofUser("user-123");
FlagContext.ofProfile("device-abc");
FlagContext.of("user-123", "device-abc");Feature flags
Read a flag by key. You never name a mode — Intempt resolves whether that key is an experiment, a personalization or a flag, so a key can change mode without your code changing.
FlagContext context = FlagContext.ofUser("user-123");
boolean on = client.boolVariation("new_checkout", context, false);
String copy = client.stringVariation("banner_copy", context, "Welcome");
Map<String, Object> all = client.allFlags(context);| Call | Returns |
|---|---|
variation(key, context, default) | the value assigned for that key |
variationDetail(key, context, default) | a FlagDetail — see below |
allFlags(context) | every key assigned to this person, in one call |
The default is required. It is what you receive on a network failure, a timeout, an unknown key
or a malformed response — so an outage degrades to your existing behaviour instead of an exception.
A flag lookup never throws for a service problem. It throws IllegalArgumentException only for a
programming mistake: a blank key, or a missing default.
Typed helpers
boolVariation, stringVariation and numberVariation return the type already converted and fall
back to the default if the served value is the wrong shape — so a flag configured as a string and
read as a boolean gives your default, not true.
variationDetail
variationDetail returns a FlagDetail<T> with three accessors: value(), reason() and
variant().
Only value() is meaningful today. The optimization/choose-api response carries name,
group and body and no reason at all, so reason() resolves to OFF on every call, and
variant() returns the selector group rather than the variant that was served. Branch on
variation and measure holdouts in Intempt, where the exposure is recorded.
Initialization and shutdown
Evaluation is remote. There is no local rule engine and no flag store to poll, so bucketing can never disagree between your code and the platform.
waitForInitialization(timeoutMillis) returns immediately. It exists so porting from a polling SDK
does not mean deleting the call. close() is present so the client works in try-with-resources and
is a no-op today.
