The traccar-realtime-client is a Java Client Software to provide full (remote) control over
and interact via live surveillance of your Traccar Server Scenario.
It can be used to observe, predict and react to live events - defined by your business.
For exmple you can control the timing of a rendez vous point for logistic vehicles.
Real Time Systems
Modern Advanced Driver Assistant Systems (ADAS) can serve as an example of Real Time Systems. They are monitoring the vehicle and observing the environment every instance of the motion. With a 5 GHz network the computational power can take place in large server farms, while the vehicle basically provides events and values from detectors.
The term real time refers to the actual computational results provided as the incident takes place.
Therefor Real Time Systems are systems that can actually interfere the incident in reality.
Today ADAS have become Self Driving Systems and can actually drive a car
and predict the trajectory by reading the road map.
A real-time system has been described as one which "controls an environment by receiving data, processing them, and returning the results sufficiently quickly to affect the environment at that time".
A system not specified as operating in real time cannot usually guarantee a response within any timeframe, although typical or expected response times may be given. Real-time processing fails if not completed within a specified deadline relative to an event; deadlines must always be met, regardless of system load.
GPS Tracking usually implies live tracking and allows us to locate something on a map. Of course live is relativ and we have to rely on connectivity and accept a little latency. For example vehicles can not be GPS tracked in most tunnels due to missing satelite information. A Real Time Client could detect this and make a prediction, when the vehicle will exit the tunnel and be GPS fixed again.
Real Timing
Structuring the data for a real-time application like a Traccar Client is crucial for performance and maintainability.
As a development guideline we do not want to use any back doors to Traccar, like a direct database access.
We treat Traccar as a mature component with endless configuration options and
we want to communicate the official way, i.e. via Traccar REST API via traccar-api-client.
Traccar is taking care of the connectivity to all (tens of thousands of different) GPS Trackers, stores there info, raises events, while we only need the one connection to the Traccar Server to interact via REST API and retrieve real time data via Websocket. Even, if we would run real-time against the Traccar Database this does not guarantee to be much faster. And there’s a risk to interfere with the Traccar controllers.
We could use an in-memory-database like h2, which is also supported in Spring Boot and Maven. Yet this would have the draw back to create objects during the real time calculation. We will create a Real Time Manager that has all objects in place and state changes occur immediately only restricted by the CPU speed.
Its a race between real time client connectivity and loading against persisting on server side.
If you place the traccar-rt-client in the same environment as your Traccar server
there are chances that the client is triggered before the database update has finished.
Nevertheless the objects are related over Traccar Database IDs, which are indispensable.
when and where
Another important aspect about 'real time development' is the usage of the provided timestamps
in chronological order: fixTime, deviceTime and serverTime.
The GPS Fixtime describes, when the Position was calculated, fixed and saved into the devices memory.
This fixtime is calculated by the GPS Unit hardware and chip in the field
with the most precise atomic clocks available.
The calculation has to be relativistic and be aware of the satelites positions and much more.
The fix is usually made when the parameters provide a result with best accuracy
and this can differ due to the environmental conditions.
|
Important
|
Real Time Developers should stick to the |
The deviceTime is the point in time when the position and event are sent.
Consecutive messages can have the same fixTime.
The serverTime is the time, when the position and event are persisted.
It can provide clues about the connectivity and network latency.
Real Time Data Structures
Traccar manages its Entities and Relations with an Entity Relational Data Model - ERM. So we need to define a robust data structure to work with Entities and Relations in the RAM, i.e. Software.
Core Design Principles
-
Centralized State
All data is held in a single, well-defined state object. -
Normalization
Each entity type (User, Device, Position, Geofence..) is stored in its own "table" ormap. Objects reference each other byIDrather than nesting the full object. This prevents data duplication and makes updates atomic. For example, aDeviceobject will contain apositionIdinstead of the entire position object. -
Maps for fast
O(1)Lookups
Data is stored in Maps where the key is the entity’sid. This allows for extremely fast lookups when an update comes in, which is essential for real-time performance.
RealTimeManager
The RealTimeManager is a thread-safe Singleton class
to manage the concurrent real-time state of the Traccar client,
also known as StateManager in RealTime context.
-
It is annotated with
@Component, so Spring creates a singleton for the application context. -
It uses
ConcurrentHashMapfor its internal state, which provides thread-safe access and updates. from WebSocket listener background threads.
private final Map<Long, User> users = new ConcurrentHashMap<>();
private final Map<Long, Device> devices = new ConcurrentHashMap<>();
private final Map<Long, Position> positions = new ConcurrentHashMap<>();
-
Synchronization is used (
deviceMapLock) to ensure atomic updates for related maps. -
The class manages real-time entities (User, Device, Position)
and their relationships safely across threads.
Note that there is no API involved.
Data Flow & Interaction
Now we need to develop methods for state modifications.
We have to load initial entities and then update them
from the live data coming in over a websocket connection.
Basically we will use the RealTimeManager in these sequentiell steps:
-
Authenticate on Traccar Server and receive a
Userobject with a database ID.
StoreUserinRealTimeManagerwithloginUser(User user). -
Load initial data for the scenario by fetching the entities from Traccar and converting them to a Map.
Optionally collect last knownPositionobjects for theDevices. -
Connect to websocket and receive live data.
Traccar pushes JSON object arrays to be transformed and then updated on individual entities.
Have a look at these RealTimeManagerIT snippets to identify the steps listed above
as you read on:
class RealTimeManagerIT extends BaseReaTimeScenarioTest { // sets up scenario
@Autowired protected Api api;
private RealTimeManager stateManager = RealTimeManager.getInstance();
// login
api.setBasicAuth(scenario.admin.getEmail(), scenario.admin.getPassword());
stateManager.loginUser(scenario.admin);
// initialize
initialUsers = api.getUsersApi().getUsers(null);
stateManager.loadInitialUsers(initialUsers);
stateManager.getAllUsers() ...
// same for devices and other entities
The last simulation of a server update is purely logical
and zero websocket technology.
The line
stateManager.addOrUpdatePosition(newPosition);
'simulates' a Position that could come in via WebSocket or any other ETL
to a controller that invokes methods to change the real time state.
Now that we can safely read from the RealTimeManager
we will create a RealTimeController for synchronization.
RealTimeController
The RealTimeManagerIT test is holding the private RealTimeManager in order to test it’s methods.
The RealTimeController is the subsequent implementation keeping the RealTimeManager private
to control it’s state by synchronizing the server updates.
The Controller encapsulates all the logic for communicating with the Traccar server.
It handles authentication, fetches the initial state via the REST API,
and then connects to the WebSocket to receive and process live updates,
feeding everything into the thread-safe state manager.
Basic RealTimeController design:
@Component (1)
public class RealTimeController {
private final RealTimeManager stateManager; (2)
public RealTimeController(RealTimeManager stateManager) { (3)
this.stateManager = stateManager;
}
@Autowired protected Api api; (4)
@Autowired private WebSocketRoute liveConnection; (5)
-
@Component: Spring creates a singleton -
private final RealTimeManagerexclusive to controller -
Instantiated by the Spring framework. Injects the RealTimeManager dependency via constructor injection.
-
Apito access the server actively -
Traccar
WebSocketRoutefor updates in the background
We will look at the TraccarWebSocketRoute soon.
For now you can run the RealTimeControllerIT
which basically executes the line
controller.loginAndInitialize(scenario.admin)
where the authentication, loading of initial server Entities and establishing a live connection via WebSocket.
RealTimeControllerIT
This test initializes Camel and rt controller
bm.traccar.rt.RealTimeControllerIT : Starting RealTimeControllerIT .. camel start .. bm.traccar.rt.RealTimeControllerIT : Started RealTimeControllerIT in 3.186 seconds
loads the scenario on the server (base test)
bm.traccar.rt.scenario.ScenarioLoader : --- Setup scenario on server ---
then the controller is authenticated via server and can load the scenario in the rt manager:
bm.traccar.rt.RealTimeController : --- Loading initial users from server... --- bm.traccar.rt.RealTimeController : --- Loading initial devices from server... ---
with server entities.
The we can see TraccarWebSocketRoute handshake to obtain a sessionId,
the creation of a VertxWebsocketEndpoint
and finally the user is logged in the rt controller:
bm.traccar.ws.TraccarWebSocketRoute : Obtained JSESSIONID: node015pugc...4ehrxl88u6sl19.node0 o.a.c.c.v.w.VertxWebsocketEndpoint : Connected to WebSocket on localhost:80 bm.traccar.rt.RealTimeController : User logged in: admin
And now the software is running an waiting for server updates:
traccarWebSocketDynamicRoute : Received Traccar WebSocket update: {"positions":[]}
traccarWebSocketMessageProcessingRoute: Process WebSocket raw message: {"positions":[]}
traccarWebSocketMessageProcessingRoute: Process WebSocket json message: {positions=[]}
Real Time Updates
As indicated the TraccarWebSocketRoute updates
the TraccarStateManager similar the the controller.
We already had chosen Apache Camel for integration purposes
and the TraccarWebSocketRoute is a complete Camel implementation
and is described in more detail
here.
sample messages
To keep a distributed systems integrity you need to have all models in mind.
The Model for Tracker Development
defines a GPS message from a unique device.
The REST yml file provides a bigger
model for a complete GTS.
These models deviate and must be mapped to each other.
The following devices and positions messages in json format look like this.
{devices=
[
{id=554, attributes={}, groupId=0, calendarId=0, name=runner, uniqueId=10, status=online,
lastUpdate=2026-02-19T19:46:41.304+00:00, positionId=198, phone=null, model=ro,
contact=null, category=null, disabled=false, expirationTime=null
}
]
}
Note the difference of the devices database id=554 and the uniqueId=10.
The database Id is technical and can change in a different environment,
while the uniqueId always refers to a unique tracker.
The latter must be used in a scenario to track the device.
Anyhow the database Ids are important for referencing.
The above device references the positionId=198,
vice versa the position has the reference deviceId=554.
{positions=
[
{id=198,
attributes={distance=0.0, totalDistance=0.0, motion=true}, deviceId=554, protocol=osmand,
serverTime=2026-02-19T19:46:41.300+00:00,
deviceTime=2026-02-19T19:46:41.000+00:00,
fixTime=2026-02-19T19:46:41.000+00:00,
valid=true, latitude=52.0, longitude=13.0, altitude=30.0, speed=10.0, course=20.0,
address=null, accuracy=0.0, network=null, geofenceIds=null
}
]
}
conclusion
This Java structure provides a clean, scalable, and safe way to manage your Traccar client’s data.
Your REST API client would call methods like loginUser and loadInitialDevices,
while your WebSocket client’s onMessage handler would call addOrUpdatePosition and/or other Entities.
The rest of your application can then safely read from the TraccarStateManager to display data.
CLI Quick Start
After creating the three layers around the ApiClient, Api interface
and RealTimeManager these are combined
in the @SpringBootApplication RealTimeClient.
run RealTimeClient CLI
The traccar-rt-client does not provide any webservices.
It is a plain command line interface (CLI) to connect to a traccar server
from the command line and read what’s going on.
@SpringBootApplication public class RealTimeClient implements CommandLineRunner
Therefor it is a solid building block for real time applications.
You can integrate it in your application and code against the
RealTimeManager as if it was the traccar server.
pick up the traccar-rt-client-6.10.0-RC.jar
put it in /someFolder/traccar-rt-client-6.10.0-RC.jar
(release url)
copy app.props
enter credentials
run java, mvn spring:run ..
start your traccar client or your tracker connected to traccar
watch the console over the map
If you don’t have a traccar server you can sign up at one of traccar’s demo servers.
RealTimeClient is a Spring Boot application that:
-
Starts RealTimeController on launch.
-
Reads admin credentials from application.properties.
-
Logs in as the admin user when starting.
-
Remains running until manually shutdown (e.g., Ctrl+C), and supports graceful shutdown.
modify RealTimeClient to a @SpringBootApplication that starts the RealTimeController and log in as traccar.admin.name as provided in the application.properties and can be gracefully shutdown manually
You can run the application as usual (e.g., with mvn spring-boot:run or java -jar), and it will log in and initialize the real-time controller using the configured admin credentials.
The Traccar WebSocket Client
The traccar-api-client is a Java Client Software to request real time data
from your Traccar Server. While the REST API is based on single requests,
i.e. REST calls and responses without any session handling, i.e. stateless.
Therefor this WebSocket Route/Session Manager can create a Camel channel for each individual registered user to manage WebSocket connections and event routing.
On a higher level different websocket channels can report live events in a given Scenario. For example you could direct different vehicles to a rendezvous point and your software can create events as they approach each other.
The Traccar WebSocket API
Our starting point is the specification at Traccar WebSocket API, which is actually so brief that we can reprint it here:
In addition to the REST API, we provide an access to a WebSocket endpoint for live updates.
Endpoint for the WebSocket connection:/api/socket
Session cookie is the only authorization option for the WebSocket connection.
Each message in the WebSocket stream uses the same universal JSON format:{ "devices": [...], "positions: [...], "events": [...] }
Websocket Handshake
Let’s break down the websocket spec above towards an implementation.
Endpoint
The primary WebSocket endpoint for Traccar is typically /api/socket.
The WebSocket URL would be ws://your.traccar.server:8082/api/socket
(or wss:// for secure connections).
Authentication
Traccar’s WebSocket API relies solely on a session cookie JSESSIONID for authentication.
You cannot use Basic Auth or Bearer tokens directly with the WebSocket connection itself.
In order to create a ws session you need to authenticate (as in traccar-api-client or traccar-api-camel)
with a successful HTTP POST request to the Traccar /api/session endpoint to log in.
Then extract the JSESSIONID cookie from the response headers of this login request
and use this JSESSIONID cookie when establishing the WebSocket connection.
WebSocket Component
As this repository is based on Spring Boot with Camel integration,
i.e. we are building a Camel Spring Boot WebSocket Client for Traccar.
Besides Spring Boot and Camel we need to choose a websocket component.
Most popular choices are the Eclipse Vert.x and the
Eclipse Jetty WebSocket Client.
Jetty is actually a traditional servlet-container with a thread based architecture in Java. As Traccar works with a Jetty Server it could be chosen for symetrie reasons. Anyhow we only want to rely on the specifications and not on proprietary implementations.
Vert.x is a modern event driven non blocking implementation comparable to netty, which we have analyzed in depth in the jeets project. Vert.x has a better scalability for a larger number of connections and a lower latency. It also offers http, database drivers and smooth integration with other technologies.
… and the winner is … Vert.x
Of course we will use the camelized version with a Spring Boot Starter in Maven
to abstract the WS component (in case we revise the decision later):
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-vertx-websocket-starter</artifactId>
With Camel we can configure the appropriate security settings,
leverage Camel’s asynchronous nature to handle multiple WebSocket connections and messages efficiently
and implement a backpressure mechanisms in case of high message volumes.
A basic route implementation looks like this:
public void configure() throws Exception {
from("vertx-websocket:ws://your-traccar-server:port/api/socket") (1)
.log("Received WebSocket message: ${body}")
.to("bean:yourMessageHandler");
}
-
use
wss://for secure connections
But first we need to extract the JSESSIONID from a http POST and create a Cookie,
while using the http context from Spring Boot for the ws connection.
Note that we will not use the traccar-api-client for the http POST,
since we clearly want to separate the two clients for API and WebSocket.
Our architecture does not want any dependencies between them for isolated testing etc.
Each client represents a software Unit and can be tested, developed and used alone.
And like every Unit it should be replaceble.
Anyhow we can combine the two in a higher level traccar-java-client.
Implementation with Camel Routes
The core of this traccar-ws-client is the
TraccarWsClientRoute.
Here is a rough outline with three routes:
@Component
public class TraccarWsClientRoute extends RouteBuilder {
@Override
public void configure() throws Exception {
from("timer:traccarLoginTimer?period=3600000") // every hour
.routeId("traccarLoginRoute") (1)
...
.setBody(simple("email=" + email + "&password=" + password)) // credentials
.toD(host + "/api/session") // login
.process(
exchange -> {
// get 'Set-Cookie' header from response
// Extract JSESSIONID from the Set-Cookie header
// set exchange property as parameter for the next ws route
// Trigger traccarWebSocketConnectionRoute (2)
})
...
.end();
from("direct:connectTraccarWebSocket")
.routeId("traccarWebSocketConnectionRoute") (2)
.process(
exchange -> {
// get JSESSIONID from Route (1)
// set Cookie Header with JSESSIONID for initial handshake
.toD("vertx-websocket:" + traccarWebSocketUrl + "&handshake.Cookie=${header.Cookie}")
.log("Connected to Traccar WebSocket.")
.to("direct:traccarWebSocketMessages"); (3)
from("direct:traccarWebSocketMessages")
.routeId("traccarWebSocketMessageProcessingRoute") (3)
.unmarshal()
.json(JsonLibrary.Jackson)
.log("Received Traccar WebSocket update: ${body}");
-
Route to trigger
http POST -
Route to connect websocket with handshake
-
Route to receive live data
Notes
-
The dynamic
vertx-websocketURL is proprietary and involves thehandshakeparameter.
The Jetty component (websocket) handles cookies different and requires an explicit header setting. -
We are not processing Cookies with
java.net.CookieHandler, CookieManager, CookieStore, CookiePolicy, HttpCookieetc.
In the firsthttproute we are simply applying String functions to extract theJSESSIONID. -
You are responsible or security using Spring Cloud Config, Kubernetes Secrets, environment variables, a secrets management solution like Vault or whatever you chose for your software.
Debugging
The initial traccar-ws-client implementation is kept as simple as it gets.
This allows a better understanding and makes it easier to expand the component
inside the application lifecycle development.
Nevertheless networking is alway a challenge and in this case you might experience problems with (reverse) proxies, firewalls, closed ports, URL / URI resolution, cloud installation, docker, port forwarding, Traccar server settings and beware of misleading AI assistance.
Therefor you can execute the most simple test with two cammand lines, before you drill deeper.
If you run into any problems apply the command line tools
curl for the http POST and wscat for the websocket connection.
In addition you should create an account on one of the graciously sponsered
Traccar Demo Servers
and test with https and email/password.
Step1: http with curl
Compose the command line with email/password/http|s/port
and check the http connection with
curl -v POST -d "email=admin@domain.com&password=admin" http://localhost:8082/api/session
and hopefully get something like this
> POST /api/session HTTP/1.1 (1)
> Host: localhost:8082
>
< Set-Cookie: JSESSIONID=node0q7h2lu4fsi40101wtkbz590i060.node0; Path=/; HttpOnly (2)
< Server: Jetty(11.0.25) (3)
<
* Connection #1 to host localhost left intact (4)
{... "name":"admin", (5)
"email":"admin@domain.com" ...}
-
>for outgoingPOST -
<for incoming response with aJSESSIONID -
Traccar’s Jetty Server version.
-
make sure connection is kept up
-
JSON DTO for logged user
Step2: ws with wscat
Again, adopt your parameters and copy the JSESSIONID from the http POST above:
wscat -c ws://localhost:8082/api/socket \
-H "Cookie: JSESSIONID=node0q7h2lu4fsi40101wtkbz590i060.node0"
Connected (press CTRL+C to quit)
< {"positions":[]}
< {}
Here you should get the Connected response and see the messages arriving in intervals
(configured on the server).
If you want to see actual values you might change something in the Traccar Frontend
or register a device or the like.
Introduce a typo or use a wrong JSESSIONID to raise
error: Unexpected server response: 503
which you might find in your java stack as
WebSocket upgrade failure: 503
To debug UpgradeRejectedException: WebSocket upgrade failure: 503 on server side
you should start here:
AsyncSocketServlet extends JettyWebSocketServlet
configure()
userId = loginService.login(token).getUser().getId();
This way you have validated all parameters and are good to go for comparing analyses as you develop.
review traccar-api-client
simple example / usage
Here’s a simple example code to demo how to add the Traccar API Service
to your company software.
First you need these prerequesites:
-
Add the
traccar-api-client-x.y.z.jarto your application.
Or add it to your.m2repo or nexus server, then to yourpom. -
Add your Traccar Server URL and credentials to your
application.propertiesfile.
i.e.host, user.name, user.password, user.email (, accountToken).
Or provide these values in a way that meets your security strategy (secrets etc.)
and then the coding is straight forward:
package your.company.app...;
import bm.traccar.api.ApiService // (1)
public class TraccarUsers {
@Autowired
private ApiService api; // (1)
public static void main(String[] args) {
api.setBasicAuth(mail, password); // (2)
// api.setBearerToken(token);
User user = new User(); // (3)
user.setName("user-1");
user.setEmail("email-1");
user.setPassword("pw-1");
User userOnServer = api.users.createUser(user); // (4)
}
}
-
add the
ApiService, being a Spring@Service class -
choose and set your authentication
and can change it any time in the program flow. -
create a
new User(DTO) in your software for your employees -
create a
new User(Entity) in your Traccar Server
The new User (DTO) is returned with a unique ID from the server.
And that is all you need to create users, devices etc.
and manage them in your code!
For more examples check the integration tests, i.e. UsersIT and others.
configuration
For convenience you can use the application.properties file
and grab the @Value in your source code, depending on your security concepts.
Check the *.*IT integration test files for demo code.
application.properties
# traccar server traccar.host=http://localhost traccar.user.name=admin traccar.user.password=admin traccar.user.email=admin@domain.com
your implementation (compare ITests)
@Value("${traccar.user.name}") private String name;
@Value("${traccar.user.password}") private String password;
@Value("${traccar.user.email}") private String mail;
usage
After adding the jar to your software or build system the API can easily be added to any Springboot Application as a @Service in your code
@Autowired private ApiService api;