Java
Send vTilt events from Java code (Spring Boot, Micronaut, Quarkus, plain Java) by POSTing to the ingest API.
There's no native Java SDK yet, but vTilt's wire format is a plain JSON POST so any Java code can emit events. The pattern below uses the JDK 11+ HttpClient and Jackson; the same shape works inside Spring Boot, Micronaut, Quarkus, and standalone tools.
#1. Add dependencies
For Spring Boot (Gradle):
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.0'groovy
For Maven:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
</dependency>xml
#2. Capture client
A singleton client with a virtual-thread (Java 21+) executor for fire-and-forget captures. Replace with Executors.newCachedThreadPool() on Java 17.
// src/main/java/com/example/vtilt/Vtilt.java
package com.example.vtilt;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public final class Vtilt {
private static final String TOKEN = System.getenv("VTILT_TOKEN");
private static final String HOST = System.getenv().getOrDefault("VTILT_HOST", "https://www.vtilt.com");
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final HttpClient CLIENT = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(2))
.build();
private static final ExecutorService EXEC = Executors.newVirtualThreadPerTaskExecutor();
private Vtilt() {}
public static void capture(String distinctId, String event, Map<String, Object> properties) {
EXEC.submit(() -> send(distinctId, event, properties == null ? Map.of() : properties));
}
public static void identify(String distinctId, Map<String, Object> properties) {
capture(distinctId, "$identify", Map.of("$set", properties));
}
private static void send(String distinctId, String event, Map<String, Object> properties) {
try {
Map<String, Object> body = new HashMap<>();
body.put("api_key", TOKEN);
body.put("event", event);
body.put("distinct_id", distinctId);
body.put("properties", properties);
HttpRequest req = HttpRequest.newBuilder(URI.create(HOST + "/api/e"))
.header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(2))
.POST(HttpRequest.BodyPublishers.ofString(MAPPER.writeValueAsString(body)))
.build();
CLIENT.send(req, HttpResponse.BodyHandlers.discarding());
} catch (Exception ignored) {
// never raise on analytics
}
}
}java
#3. Capture events
import com.example.vtilt.Vtilt;
import java.util.Map;
public class CheckoutService {
public void completePurchase(String userId, double amount) {
Vtilt.identify(userId, Map.of("plan", "pro"));
Vtilt.capture(userId, "purchase_completed", Map.of(
"amount", amount,
"currency", "USD"
));
}
}java
#4. Spring Boot controller
@RestController
public class CheckoutController {
@PostMapping("/checkout")
public Map<String, Boolean> complete(@RequestBody CheckoutRequest req) {
Vtilt.capture(req.userId(), "purchase_completed", Map.of("amount", req.amount()));
return Map.of("ok", true);
}
}java
#Next steps
- Identify & alias — full identification model.
- Event forwarding — fan events out to GA4, Meta CAPI, PostHog.
- Reverse proxy — block-resistant ingestion.