OpenPanel

Java

The OpenPanel Java SDK allows you to track user behavior in your JVM backend applications.

The OpenPanel Java SDK allows you to track user behavior in your JVM backend applications. It targets Java 11+ and works with Spring Boot, Quarkus, Micronaut, plain Java, and more.

View the Java SDK on GitHub for the latest updates and source code.

For Android/Kotlin applications, see the Kotlin SDK instead.

Installation

Step 1: Add Dependency

Add the OpenPanel SDK to your project's dependencies:

Maven

<dependency>
    <groupId>fr.idcapture</groupId>
    <artifactId>openpanel-java</artifactId>
    <version>0.4.0</version>
</dependency>

Gradle (Groovy)

implementation 'fr.idcapture:openpanel-java:0.4.0'

Gradle (Kotlin DSL)

implementation("fr.idcapture:openpanel-java:0.4.0")

Step 2: Initialize

Import the SDK and initialize it with your client ID and secret:

import fr.idcapture.openpanel.OpenPanel;
import fr.idcapture.openpanel.OpenPanelOptions;

OpenPanel op = OpenPanel.create(
    OpenPanelOptions.builder()
        .clientId("YOUR_CLIENT_ID")
        .clientSecret("YOUR_CLIENT_SECRET")
        .build()
);

Configuration Options

Common options
  • apiUrl - The url of the openpanel API or your self-hosted instance
  • clientId - The client id of your application
  • clientSecret - The client secret of your application (only required for server-side events)
  • filter - A function that will be called before sending an event. If it returns false, the event will not be sent
  • disabled - If true, the library will not send any events

Additional Java-specific options:

  • apiUrl - API endpoint URL (default: https://api.openpanel.dev)
  • disabled - Set to true to disable all event tracking
  • filter - A function that will be called before tracking an event. If it returns false, the event will not be tracked
  • connectTimeoutSeconds - Connection timeout in seconds (default: 10)
  • readTimeoutSeconds - Read timeout in seconds (default: 30)
  • maxRetries - Maximum number of retries for failed requests (default: 3, set to 0 to disable)
  • initialRetryDelayMs - Initial retry delay in milliseconds (default: 500, doubles each attempt)
  • verbose - Set to true to enable verbose logging via java.util.logging

Full configuration example

OpenPanel op = OpenPanel.create(
    OpenPanelOptions.builder()
        .clientId("YOUR_CLIENT_ID")
        .clientSecret("YOUR_CLIENT_SECRET")
        .apiUrl("https://api.openpanel.dev")
        .disabled(false)
        .filter(name -> !name.startsWith("debug_"))
        .connectTimeoutSeconds(10)
        .readTimeoutSeconds(30)
        .maxRetries(3)
        .initialRetryDelayMs(500)
        .verbose(false)
        .build()
);

Usage

All methods return CompletableFuture<Void>. You can ignore the future (fire-and-forget) or chain callbacks for error handling.

Tracking Events

To track an event:

// Minimal
op.track("page_viewed");

// With properties
op.track("button_clicked", Map.of("button_id", "submit_form"));

// With user
op.track("checkout_started", Map.of("cart_value", 149.99), "user123");

// With user + groups
op.track("report_exported",
    Map.of("format", "pdf"),
    "user123",
    List.of("org_acme")
);

Identifying Users

To identify a user:

// With custom properties only
op.identify("user123", Map.of("plan", "enterprise"));

// With standard fields + custom properties
op.identify("user123", "John", "Doe", "john@example.com", Map.of("tier", "premium"));

// With avatar
op.identify("user123", "John", "Doe", "john@example.com",
    "https://example.com/avatar.png", Map.of("tier", "premium"));

Setting Global Properties

Properties set here are merged into every track() call. Caller properties take precedence over global ones.

op.setGlobalProperties(Map.of(
    "app_version", "2.1.0",
    "env", "production"
));

// All subsequent track() calls will include app_version and env automatically
op.track("feature_used", Map.of("feature", "export"));

Incrementing Properties

To increment a numeric property on a user profile:

op.increment("user123", "login_count", 1);

Decrementing Properties

To decrement a numeric property on a user profile:

op.decrement("user123", "credits", 5);

Tracking Revenue

To track revenue events:

// Simple
op.revenue(99.99);

// With user
op.revenue(99.99, "user123");

// With user + extra properties
op.revenue(49.99, "user123", Map.of("currency", "EUR", "plan", "pro"));

Groups

// Create or update a group
op.group("org_acme", "company", "Acme Inc", Map.of("plan", "enterprise", "seats", 25));

// Assign a user to groups
op.assignGroup("user123", List.of("org_acme"));

Groups are not automatically attached to track events. Pass them explicitly on each track() call where needed.

Shutdown

Shutdown the client cleanly when your application stops:

// Explicit
op.close();

// Or via try-with-resources
try (OpenPanel op = OpenPanel.create(options)) {
    op.track("startup");
}

Advanced Usage

Error Handling

On API errors (4xx/5xx), the CompletableFuture is completed exceptionally with an HttpTracker.OpenPanelApiException containing the HTTP status code:

op.track("event")
  .exceptionally(e -> {
      if (e.getCause() instanceof HttpTracker.OpenPanelApiException apiEx) {
          logger.warn("OpenPanel returned {}", apiEx.getStatusCode());
      }
      return null;
  });

Retry Behavior

Failed requests (5xx and network errors) are retried automatically with exponential backoff. Defaults: 3 retries, starting at 500ms (500ms → 1s → 2s). Client errors (4xx) are not retried.

// Customize retry behavior
OpenPanelOptions.builder()
    .clientId("id")
    .maxRetries(5)              // more retries
    .initialRetryDelayMs(1000)  // start at 1s
    .build();

// Disable retries entirely
OpenPanelOptions.builder()
    .clientId("id")
    .maxRetries(0)
    .build();

Custom Event Filtering

You can filter events by name before they are sent:

OpenPanelOptions.builder()
    .clientId("YOUR_CLIENT_ID")
    .filter(eventName -> !eventName.startsWith("internal_"))
    .build();

Disabling Tracking

Useful for local development or testing — no HTTP calls are made:

OpenPanelOptions.builder()
    .clientId("YOUR_CLIENT_ID")
    .disabled(true)
    .build();

Self-Hosted OpenPanel

If you're running a self-hosted OpenPanel instance, set the apiUrl:

OpenPanelOptions.builder()
    .clientId("YOUR_CLIENT_ID")
    .apiUrl("https://your-openpanel-instance.com")
    .build();

Debug Logging

Enable verbose mode to log all HTTP requests and responses via java.util.logging:

OpenPanelOptions.builder()
    .clientId("YOUR_CLIENT_ID")
    .verbose(true)
    .build();

Kotlin Interop

All property maps use JetBrains @Nullable type-use annotations (Map<String, @Nullable Object>), so Kotlin sees Map<String, Any?> natively — no @Suppress("UNCHECKED_CAST") needed.

op.track("checkout", mapOf("amount" to 49.99, "coupon" to null))

Community SDK

The Java SDK is a community-maintained SDK by idcapture. For issues or feature requests, please file an issue on the Java SDK GitHub repository.

On this page