Real-time streaming

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:

  1. KATSANA Telematics Ingestion: On-board GPS hardware devices transmit live telematics over cellular networks to KATSANA’s high-availability collectors.
  2. Redis Pub/Sub Backbone: Telematics packets are routed through distributed Redis message brokers across dedicated channels (track.position:*, status:*, connect:*, disconnect:*).
  3. 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 authenticate event 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:

  1. It extracts your user ID and queries permissions for all vehicles assigned to your account.
  2. It automatically subscribes your socket connection to the corresponding vehicle IMEI event channels.
  3. 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: