WebSocket integration
Connect to KATSANA's real-time WebSocket service for low-latency vehicle tracking, telemetry, and status events.
Overview
KATSANA’s WebSocket gateway provides high-throughput, low-latency vehicle tracking and telemetry using Socket.IO protocol over WebSockets. The service broadcasts real-time GPS coordinates, vehicle movement states, battery voltages, speed, ignition signals, and device connectivity events directly to authenticated clients.
Key capabilities
- Real-time GPS updates: Stream live location coordinates as vehicles travel.
- Vehicle state classification: Automated detection of moving, idling, stopped, and offline states.
- Device lifecycle events: Instant notification when telematics units connect or disconnect.
- Automatic fleet subscription: Authenticated sessions automatically subscribe to all vehicles authorized under your account without manual channel joining.
- Standardized payloads: Consistent JSON message schemas across JavaScript, Python, mobile, and browser clients.
Architecture
The real-time streaming pipeline consists of:
- KATSANA Telematics Ingestion: On-board GPS hardware devices transmit live telematics over cellular networks to KATSANA’s high-availability collectors.
- Redis Pub/Sub Backbone: Telematics packets are routed through distributed Redis message brokers across dedicated channels (
track.position:*,status:*,connect:*,disconnect:*). - WebSocket Proxy Cluster: Node.js Socket.IO proxy nodes validate incoming client JWT tokens, inspect user fleet permissions, and route authorized vehicle streams to connected clients.
| Parameter | Specification | Description |
|---|---|---|
| Protocol | wss:// (Secure WebSocket) or ws:// |
Socket.IO protocol transport (websocket, fallback to polling) |
| Default Port | 3000 |
Configured port on the streaming host |
| Server Host | wss://my.katsana.com:3000 |
Gateway endpoint (or your dedicated enterprise cluster hostname) |
| Socket Path | /socket.io |
Default Socket.IO client connection path |
Authentication
WebSocket connections use token-based authentication via JSON Web Tokens (JWT).
1. Obtain a JWT token
Before connecting to the WebSocket server, send your credentials to the KATSANA API authentication endpoint:
POST /api/auth HTTP/1.1
Host: api.katsana.com
Content-Type: application/json
{
"username": "[email protected]",
"password": "your-password"
}
A successful response returns a signed JWT token:
{
"token": "<your-jwt-token>"
}
2. 15-second authentication window
Important: The WebSocket server enforces a strict 15-second authentication timeout. Once the raw TCP/WebSocket connection is opened, your client must emit the
authenticateevent with your token within 15 seconds. If no valid authentication event is received within this window, the server terminates the connection.
3. Automatic vehicle subscription
When the server validates your JWT token:
- It extracts your user ID and queries permissions for all vehicles assigned to your account.
- It automatically subscribes your socket connection to the corresponding vehicle IMEI event channels.
- Live data begins streaming immediately—no manual room join or subscription command is required.
Connection lifecycle
Follow this four-step sequence to maintain a resilient connection:
[Client] [KATSANA WebSocket Server]
│ │
│──── 1. Connect (ws/wss with Socket.IO) ─────────>│
│<─── 2. 'connect' event (socket.id assigned) ─────│
│ │
│──── 3. emit('authenticate', { token }) ─────────>│
│ │ (Validates JWT &
│ │ queries authorized IMEIs)
│<─── 4. 'authenticated' event ────────────────────│
│ │
│<═══ 5. Broadcasts: track:{imei}, status:{imei} ══│
Connection configuration
Recommended Socket.IO options for enterprise resilience:
const socket = io('wss://my.katsana.com:3000', {
transports: ['websocket', 'polling'],
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
reconnectionAttempts: 10,
forceNew: true,
path: '/socket.io'
});
Event types & payload schemas
Once authenticated, your client receives structured events for every authorized vehicle.
1. Position tracking (track:{imei})
Emitted whenever a new GPS reading is recorded for vehicle device {imei}.
{
"status": 200,
"data": {
"imei": "123456789012345",
"current": {
"state": "moving",
"latitude": 3.1390,
"longitude": 101.6869,
"tracked_at": "2026-01-27 03:48:00",
"voltage": 12.5,
"speed": 65,
"gsm": 28,
"satellites": 12,
"ignition": true,
"ev": {
"status": null,
"charge": null
}
}
}
}
Field reference
| Property | Type | Description |
|---|---|---|
imei |
string |
15-digit International Mobile Equipment Identity of the tracker. |
state |
string |
Calculated movement status: moving, idling, stopped, or offline. |
latitude |
number |
WGS 84 latitude coordinate in decimal degrees. |
longitude |
number |
WGS 84 longitude coordinate in decimal degrees. |
tracked_at |
string |
UTC timestamp recorded by the hardware device (YYYY-MM-DD HH:mm:ss). |
voltage |
number |
Main vehicle battery voltage level (in Volts). |
speed |
number |
Speed over ground in kilometres per hour (km/h). |
gsm |
number |
Cellular signal quality index (CSQ, typically 0–31). |
satellites |
number |
Count of locked GPS/GLONASS satellites used in the fix. |
ignition |
boolean |
Engine ignition status (true = ON, false = OFF). |
ev.status |
string|null |
Electric vehicle charging/power state (if EV telemetry is equipped). |
ev.charge |
number|null |
High-voltage traction battery state of charge percentage (0–100%). |
Vehicle states
| State | Evaluated condition | Description |
|---|---|---|
moving |
speed > 0 |
Vehicle is traveling on the road. |
idling |
speed == 0 && ignition == true |
Vehicle is stationary with the engine running. |
stopped |
speed == 0 && ignition == false |
Vehicle is parked with the ignition turned off. |
offline |
Elapsed silence > 24 hours | No telemetry received from the unit for over 1,440 minutes. |
2. Status alerts (status:{imei})
Emitted when custom sensor thresholds or diagnostic states change (e.g., geofence triggers, battery disconnection, panic alerts):
{
"status": 200,
"data": {
"type": "battery_cut",
"description": "Main battery power disconnected",
"timestamp": "2026-01-27 03:49:15"
}
}
3. Device connection (connect:{imei})
Broadcast when a vehicle’s telematics hardware establishes a fresh TCP socket with KATSANA’s edge receivers:
{
"status": 200
}
4. Device disconnection (disconnect:{imei})
Broadcast when a tracker terminates communication or enters sleep mode:
{
"status": 200
}
5. Synthetic health channel (track:999999999999999)
The gateway emits a synthetic heartbeat message once every 60 seconds on IMEI 999999999999999 to allow client health checks. Production applications should ignore or filter this test IMEI.
Code examples
Node.js / JavaScript client
Using socket.io-client (v2.x or v4.x compatible):
import { io } from 'socket.io-client';
const API_URL = 'https://api.katsana.com';
const WS_URL = 'wss://my.katsana.com:3000';
async function getJwtToken() {
const response = await fetch(`${API_URL}/api/auth`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: process.env.KATSANA_USERNAME,
password: process.env.KATSANA_PASSWORD,
}),
});
if (!response.ok) {
throw new Error(`Authentication failed with HTTP ${response.status}`);
}
const payload = await response.json();
return payload.token;
}
async function startStreaming() {
const token = await getJwtToken();
const socket = io(WS_URL, {
transports: ['websocket', 'polling'],
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
reconnectionAttempts: 10,
});
socket.on('connect', () => {
console.log(`Connected to KATSANA WebSocket (socket ID: ${socket.id})`);
// Authenticate within the 15-second window
socket.emit('authenticate', { token });
});
socket.on('authenticated', () => {
console.log('Session authenticated. Streaming authorized vehicle updates...');
});
socket.on('unauthorized', () => {
console.error('Authentication rejected. Verify credentials and Enterprise entitlement.');
socket.disconnect();
});
// Socket.IO wildcard listener pattern:
const originalOnevent = socket.onevent;
socket.onevent = function (packet) {
const [eventName, data] = packet.data || [];
if (originalOnevent) originalOnevent.call(this, packet);
if (!eventName) return;
const [eventType, imei] = eventName.split(':');
// Skip synthetic heartbeat channel
if (imei === '999999999999999') return;
if (eventType === 'track' && data?.status === 200) {
const v = data.data.current;
console.log(`[${v.tracked_at}] Vehicle ${imei} (${v.state}): ${v.latitude}, ${v.longitude} at ${v.speed} km/h`);
} else if (eventType === 'status') {
console.log(`[Status Event] Vehicle ${imei}:`, data);
} else if (eventType === 'connect') {
console.log(`[Device Online] Vehicle ${imei} connected`);
} else if (eventType === 'disconnect') {
console.log(`[Device Offline] Vehicle ${imei} disconnected`);
}
};
socket.on('disconnect', (reason) => {
console.warn('Socket disconnected:', reason);
});
}
startStreaming().catch(console.error);
Python client
Using python-socketio and requests:
import os
import requests
import socketio
API_URL = os.getenv("API_URL", "https://api.katsana.com")
WS_URL = os.getenv("WS_URL", "wss://my.katsana.com:3000")
def get_jwt_token():
res = requests.post(
f"{API_URL}/api/auth",
json={
"username": os.environ["KATSANA_USERNAME"],
"password": os.environ["KATSANA_PASSWORD"],
},
timeout=10,
)
res.raise_for_status()
return res.json()["token"]
sio = socketio.Client(reconnection=True, reconnection_delay=1, reconnection_delay_max=5)
@sio.on("connect")
def on_connect():
print(f"Connected to gateway: {sio.sid}")
token = get_jwt_token()
sio.emit("authenticate", {"token": token})
@sio.on("authenticated")
def on_authenticated():
print("Authentication successful. Receiving vehicle telemetry...")
@sio.on("unauthorized")
def on_unauthorized():
print("Gateway authorization rejected.")
sio.disconnect()
@sio.on("*")
def catch_all(event, data):
parts = event.split(":")
if len(parts) == 2:
event_type, imei = parts
if imei == "999999999999999":
return
if event_type == "track" and data.get("status") == 200:
current = data["data"]["current"]
print(f"Vehicle {imei} ({current['state']}): {current['latitude']}, {current['longitude']} @ {current['speed']} km/h")
if __name__ == "__main__":
sio.connect(WS_URL, transports=["websocket", "polling"])
sio.wait()
Troubleshooting
| Symptom | Cause | Resolution |
|---|---|---|
| Connection refused / timeout | Port 3000 is blocked by an outbound firewall or proxy. |
Ensure outbound TCP port 3000 is permitted in network security groups, or connect via standard 443 SSL reverse proxy if provisioned for your enterprise. |
| Connection closes after ~15s | Client failed to emit authenticate in time. |
Ensure your application calls socket.emit('authenticate', { token }) immediately inside the connect event handler. |
unauthorized event |
Expired JWT or missing Enterprise subscription. | Refresh the token via GET /api/auth/refresh or re-authenticate. Verify that your account has been provisioned with the KATSANA Enterprise tier. |
| Connected but no vehicle events | Account has no active trackers or incorrect IMEI mapping. | Verify vehicle assignment in the KATSANA Customer Portal and check that devices are actively reporting data. |
| Unexpected test vehicle data | Synthetic health check broadcast. | Filter out events where IMEI is 999999999999999 in your packet handler. |
Downloads
Download the ready-to-run JavaScript starter repository including connection templates, environment configurations, and Docker definitions: