Live Tracking & WebSocket
Stream vehicle positions over a WebSocket — the architecture, the authenticated channel, the public tracking channel, and how it behaves under load.
Yipii streams live vehicle positions over a socket.io connection to the AVL server. This page is the contract: how to connect, what you get, and why what you get may be smaller than you expected.
Architecture
Trackers send positions over cellular to the AVL server, which decodes the protocol,
enriches the fix (address, status, trip, sensors) and pushes it straight out to connected
socket.io clients. The REST API on api.yipii.io is a separate service reading the stored,
grouped history.
| What you need | Where it lives |
|---|---|
| REST API — assets, history, reports | https://api.yipii.io |
| Live position stream | https://avl.dazzlepanel.com (socket.io) |
The live stream is still served from the dazzlepanel.com host. It is the same platform —
the DNS move to a yipii.io name has not happened yet. Point integrations at
avl.dazzlepanel.com and expect an announced change.
The stream is not a Pusher/Reverb channel. ws-live.yipii.io exists, but the only things
on it are public tracking links, in-app user notifications and
driver messaging. There is no channel that carries a fleet's positions, and subscribing to one
gets you a connection that never emits.
Live positions over socket.io
Connect
One socket.io connection per account, carrying every asset you want. The token and the asset list are query parameters on the handshake.
Get the asset ids from GET /api/{account_key}/asset_map — see
the integrator setup guide.
Handshake parameters
| Parameter | Required | What it does |
|---|---|---|
access_token | yes | Your Bearer token, without the Bearer prefix. Validated on every connect against the account's entitlements; a bad token is disconnected, not downgraded |
asset_ids | yes | JSON array of asset ids. Ids your account cannot see are dropped silently before any data flows — an empty result means an empty stream, not an error |
style | no | detailed requests the full payload. It only has an effect on a plan that includes Detailed data — see below. Omit it, and on any other plan, you get the standard payload |
channels | no | JSON array or comma-separated. location, alert, vehicle_health, driver_behavior. Defaults to location only, and location is always included whatever you ask for |
Events
The socket.io event name is the message type, and the payload is the object itself — there is no envelope to unwrap.
| Event | Fires when | Needs |
|---|---|---|
location | A position is decoded, and on connect | Always on |
alert | A configured alert fires | channels + an entitled account |
vehicle_health | A health snapshot is computed | channels + Mobility on the account |
driver_behavior | A behaviour event is scored | channels + a driver add-on |
The first location message is an array — the last known position of every asset you
subscribed to. Everything after it is a single object. Handle both, as the example above does.
Out-of-order frames are dropped server-side per asset, so you will not see a position go
backwards in time. Do not rely on dateUpdated for ordering; wsSeq is the monotonic
sequence the server orders by.
Standard and detailed data
This is the part that surprises integrators. The standard payload is the default, always — a token alone does not buy the detailed one.
Detailed data is a paid tier. Two things have to be true to receive it:
- The account's plan includes Detailed data.
- The connection asks for it, with
style=detailed.
Miss either and you get the standard payload. There is no error and no warning — the connection
succeeds and the payload is smaller. Sending style=detailed on a plan without the tier is
harmless and changes nothing.
Detailed data, and the alert / vehicle_health / driver_behavior channels, are
commercial. If you need them, that is a conversation with Yipii about the plan on the account
— not a parameter you can add your way into.
What the standard payload contains
Exactly ten fields, and nothing else:
assetId · trackerImei · latitude · longitude · speed · course · dateUpdated ·
wsSeq · dateMoved · status
status is reduced to { "name": "Moving" | "Parked", "color": "#333333" } — derived from
whether speed is above zero, not the real status engine.
The standard payload is also throttled to one frame per asset per 25 seconds, and carries
no alert, vehicle_health or driver_behavior whatever you subscribe to.
What detailed adds
The complete decoded record: the real status object with its thresholds and colour, the
resolved geoPoint address, sensors, beacons, the full ioData list, startStopTrip
with its coordinate trail and scores, power, battery, gpsSignal, driverId, protocol,
tracker, and more. No throttle. A worked example is in
the integrator setup guide.
Which channels you get
Channels come with the plan, per account rather than per key:
| Channel | Included with |
|---|---|
location | Every plan |
alert | Detailed data |
vehicle_health | Detailed data, on an account with Yipii Mobility |
driver_behavior | Detailed data, plus a driver add-on |
Channels you ask for but are not on your plan are dropped silently at connect. If you
subscribed to vehicle_health and never see one, check the plan before the code.
Why the default is the standard payload
The stream is one connection carrying a whole account's traffic at whatever rate the trackers report. The detailed record is roughly an order of magnitude larger and includes a trip's entire coordinate trail on every frame. The standard payload exists so that a consumer who only draws dots on a map costs what drawing dots on a map should cost.
Connection etiquette
The stream is built for one persistent connection per account, holding every asset you care about. It is not built for a connection per asset, and a fleet opened that way will be throttled or refused.
- Persist the connection. Reconnect with backoff; do not reconnect per request.
- Batch the asset list. One socket with 300 ids, not 300 sockets.
- Cache the token. It is valid for a year; fetching a new one per connect is unnecessary load on the auth server.
- Expect the first frame to be a batch, and size your handler for it.
Public Tracking WebSocket
For public tracking links where viewers don't have full API credentials. Uses session-based authentication with the same WebSocket server.
Overview
Step 1: Get Link Info
Check the tracking link's access mode and status (no auth required):
Access modes:
| Mode | Verification Required |
|---|---|
public | None — call verify with empty body |
email | Email address |
email_code | Email + 6-digit code (sent via email) |
authorized_only | Whitelisted email address |
Step 2: Verify and Get Session Token
Public mode (no credentials):
Email mode:
Email + code mode (two requests):
Response:
The session token is valid for 4 hours by default.
Step 3: Connect WebSocket
Step 4: Subscribe to Channel
Step 5: Listen for Events
| Event | Description |
|---|---|
.location.updated | Vehicle position changed |
.link.expired | Tracking link expired or disabled |
.schedule.changed | Entered or exited schedule window |
.vehicle.changed | Route-based link reassigned to different vehicle |
Location Event Payload
Note: No internal identifiers (asset_id, IMEI, account info) are exposed. The distance_km and eta_minutes fields are only present when the link has arrival-based expiration configured.
Polling Fallback
If WebSocket is unavailable, poll the location endpoint every 30 seconds:
The response includes asset data with location fields matching the WebSocket payload structure.
Swift (iOS)
Kotlin (Android)
Security
Data Exposed to Public Tracking Viewers
| Exposed | NOT Exposed |
|---|---|
| Position (lat/lng) | IMEI number |
| Speed and heading | Internal device IDs |
| Moving/stopped status | Account information |
| Address (street, town) | Track history |
| ETA and distance to destination | Other assets |
| Display name | Driver personal data |
Session Security
- Session tokens are high-entropy random strings tied to a specific tracking link UUID
- Cross-link protection — a session for link A cannot access link B's channel
- Expiration — sessions expire after a configurable period (default 4 hours)
- TLS required — all connections use WSS (port 443)
- Revocation — disabling a link immediately disconnects all viewers
Access Control for Public Tracking
| Mode | Security Level | Use Case |
|---|---|---|
public | Lowest | Customer delivery tracking |
email | Medium | Known recipients (parents, partners) |
email_code | High | Sensitive cargo, compliance |
authorized_only | Highest | Restricted access (warehouse staff) |
Live stream security
- The token is validated on every connect, not only when you ask for detail. A rejected token is disconnected — it is never quietly downgraded to a smaller payload.
asset_idsis treated as hostile input. It is intersected with the assets your account can actually see, and anything else is dropped before you are registered for broadcasts.- Non-granted channels are dropped, silently, at connect.
- It fails closed. If the auth service cannot be reached and there is no recent cached result for your token, the connection is refused rather than served unscoped. A previously-validated token keeps working across a short outage.
Scaling & Performance
Ask for the assets you need, on one connection
Each asset produces a position every 10-30 seconds while moving. Subscribing to 1,000 when you draw 10 wastes bandwidth at both ends.
Narrow the asset_ids list, not the number of connections. There is no per-asset channel,
and opening a socket per asset is the one pattern this server is not built for:
Deduplication
GPS trackers may send duplicate positions. Deduplicate by assetId + wsSeq — wsSeq is the server's monotonic counter, and unlike dateUpdated it never goes backwards:
Reconnection
Pusher clients reconnect automatically with exponential backoff. For public tracking, validate the session before reconnecting:
Rate Limits
Public Tracking:
| Endpoint | Limit |
|---|---|
POST /verify | 30 requests/minute per IP |
GET /location (polling) | 60 requests/minute per session |
| WebSocket connections per IP | 100 |
| Messages per second per channel | 10 |
Typical Update Frequency:
| Vehicle State | Update Interval |
|---|---|
| Moving | Every 10-30 seconds |
| Stopped, ignition on | Every 60 seconds |
| Stopped, ignition off | Every 5-10 minutes |
WebSocket Authentication Errors
| Code | Meaning |
|---|---|
| 4001 | Invalid session token |
| 4002 | Session expired |
| 4003 | Tracking link not found |
| 4004 | Link expired or inactive |
| 4005 | Outside schedule window |
Next Steps
- Live Demo — Interactive sandbox with simulated WebSocket flow
- Reporting Service — Async report generation
- Tracking Links — Creating and managing public tracking links
- IoT-BE API Reference — Full REST API documentation
- Integrator setup — key, asset list and a live connection, end to end
- Authentication — OAuth2 token setup
Was this page helpful?