WebSocket API Reference

WebSocket API Reference

Real-time aviation data at your fingertips. SkySpy provides live streaming through Django Channels WebSocket connections with intelligent rate limiting, delta compression, and automatic reconnection.


Overview

SkySpy's WebSocket API delivers real-time bidirectional communication for tracking aircraft, monitoring safety events, and streaming aviation data.

graph LR
    subgraph Clients
        A[Web App]
        B[Mobile App]
        C[Python Script]
    end

    subgraph SkySpy Server
        D[WebSocket Gateway]
        E[Django Channels]
        F[Redis Pub/Sub]
    end

    A -->|wss://| D
    B -->|wss://| D
    C -->|wss://| D
    D --> E
    E <--> F

What You Can Stream

ChannelDescriptionUse Case
AircraftLive ADS-B position updatesReal-time tracking map
SafetyTCAS alerts, emergency squawks, conflictsSafety monitoring
AlertsCustom rule-based notificationsPersonalized alerts
ACARS/VDL2Datalink messagesMessage decoding
StatisticsLive analytics and metricsDashboard widgets
AirspaceAdvisories, NOTAMs, TFRsAirspace awareness

Key Features

Note: SkySpy's WebSocket implementation is optimized for both high-performance servers and resource-constrained devices like Raspberry Pi.

FeatureDescription
Rate LimitingPer-topic rate limits optimize bandwidth
Message BatchingHigh-frequency updates collected into efficient batches
Delta UpdatesOnly changed fields sent for position updates
HeartbeatPing/pong keepalive every 30 seconds
Auto-reconnectExponential backoff with jitter
Topic SubscriptionsSubscribe only to the data you need

Connection URLs

All WebSocket endpoints follow this pattern:

wss://{host}/ws/{endpoint}/

Available Endpoints

Tip: Use the Combined Feed (/ws/all/) for most applications. It provides all data streams through a single connection.

EndpointPathBadgeDescription
Combined Feed/ws/all/AllAll data streams in one connection
Aircraft/ws/aircraft/AircraftAircraft positions and updates
Airspace/ws/airspace/AirspaceAdvisories, boundaries, weather
Safety/ws/safety/SafetyTCAS, emergencies, conflicts
ACARS/ws/acars/ACARSACARS/VDL2 messages
Audio/ws/audio/AudioRadio transcription updates
Alerts/ws/alerts/AlertsCustom alert triggers
NOTAMs/ws/notams/NOTAMsNOTAMs and TFRs
Stats/ws/stats/StatsStatistics and analytics
Cannonball/ws/cannonball/MobileMobile threat detection

Authentication

Connection Handshake Flow

sequenceDiagram
    participant C as Client
    participant S as Server
    participant A as Auth Service

    C->>S: WebSocket Connect (with token)
    S->>A: Validate Token
    A-->>S: Token Valid
    S-->>C: Connection Accepted
    S->>C: Initial Snapshot
    C->>S: Subscribe to Topics
    S-->>C: Subscription Confirmed

    loop Real-time Updates
        S->>C: Stream Data
    end

Authentication Modes

ModeStatusBehavior
publicOpenAll connections allowed without authentication
hybridMixedAnonymous access to public features, auth required for private
privateLockedAll connections require valid authentication

Token Methods

Warning: Query string tokens are logged by most web servers. Use the header method in production.

Header (Recommended):

// Recommended: Sec-WebSocket-Protocol Header
const ws = new WebSocket(url, ['Bearer', 'eyJhbGciOiJIUzI1NiIs...']);

Query String (Discouraged):

// Discouraged: Query String
const ws = new WebSocket('wss://example.com/ws/all/?token=eyJhbGciOiJIUzI1NiIs...');

Supported Token Types

Token TypeFormatExample
JWT Access TokeneyJ...From /api/auth/token/ endpoint
API Key (Live)sk_live_...Production API key
API Key (Test)sk_test_...Development API key

Message Protocol

Message Flow Diagram

sequenceDiagram
    participant C as Client
    participant S as Server

    Note over C,S: Client Actions
    C->>S: {"action": "subscribe", "topics": ["aircraft"]}
    S-->>C: {"type": "subscribed", "topics": ["aircraft"]}

    Note over C,S: Server Events
    S->>C: {"type": "aircraft:snapshot", "data": {...}}
    S->>C: {"type": "aircraft:update", "data": {...}}

    Note over C,S: Request/Response
    C->>S: {"action": "request", "type": "aircraft-info", "request_id": "123"}
    S-->>C: {"type": "response", "request_id": "123", "data": {...}}

    Note over C,S: Heartbeat
    C->>S: {"action": "ping"}
    S-->>C: {"type": "pong"}

Client-to-Server Actions

ActionDescriptionParameters
subscribeSubscribe to topicstopics: string[]
unsubscribeUnsubscribe from topicstopics: string[]
pingHeartbeat pingNone
requestRequest/response querytype, request_id, params
{
  "action": "subscribe",
  "topics": ["aircraft", "safety"]
}

Server-to-Client Events

Server messages use a type field with namespace prefix:

{
  "type": "aircraft:update",
  "data": { }
}

Batch Messages

Info: High-frequency updates are batched for efficiency. Critical messages like alert, safety, and emergency bypass batching for immediate delivery.

{
  "type": "batch",
  "messages": [
    { "type": "aircraft:update", "data": {} },
    { "type": "aircraft:update", "data": {} }
  ],
  "count": 2,
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Request/Response Pattern

For on-demand queries, use the request/response pattern with a unique request_id.

Message Structure

graph LR
    subgraph Request
        A[action: request] --> B[type: aircraft-info]
        B --> C[request_id: req_123]
        C --> D[params: icao: A1B2C3]
    end

    subgraph Response
        E[type: response] --> F[request_id: req_123]
        F --> G[data: ...]
    end

    D -.->|Server Processing| E

Request:

{
  "action": "request",
  "type": "aircraft-info",
  "request_id": "req_abc123",
  "params": {
    "icao": "A1B2C3"
  }
}

Success Response:

{
  "type": "response",
  "request_id": "req_abc123",
  "request_type": "aircraft-info",
  "data": {
    "icao_hex": "A1B2C3",
    "registration": "N12345",
    "type_code": "B738",
    "operator": "Southwest Airlines"
  }
}

Error Response:

{
  "type": "error",
  "request_id": "req_abc123",
  "message": "Aircraft not found"
}

Aircraft Consumer

Endpoint: /ws/aircraft/

Real-time aircraft position tracking with high-frequency updates, delta compression, and message batching.

Topics

TopicBadgeDescription
aircraftaircraftAll aircraft updates
statsstatsFiltered statistics
allallCombined feed

Event Types

EventTriggerDescription
aircraft:snapshotOn connectFull state of all tracked aircraft
aircraft:updatePeriodic (rate-limited)Full aircraft list update
aircraft:newNew detectionNew aircraft detected in range
aircraft:removeTimeout/out of rangeAircraft no longer tracked
aircraft:deltaPosition changeOnly changed fields (RPi optimization)
aircraft:heartbeatEvery 5 secondsCount and timestamp only

aircraft:snapshot

Sent immediately on connection with the current aircraft state.

{
  "type": "aircraft:snapshot",
  "data": {
    "aircraft": [
      {
        "hex": "A1B2C3",
        "flight": "SWA1234",
        "lat": 33.9425,
        "lon": -118.4081,
        "alt_baro": 35000,
        "gs": 450,
        "track": 270,
        "baro_rate": 0,
        "squawk": "1200",
        "category": "A3",
        "is_military": false,
        "distance_nm": 25.4
      }
    ],
    "count": 42,
    "timestamp": "2024-01-15T10:30:00.000Z"
  }
}

aircraft:delta

Tip: Delta updates significantly reduce bandwidth on constrained connections. Only changed fields are transmitted.

{
  "type": "aircraft:delta",
  "data": {
    "hex": "A1B2C3",
    "changes": {
      "lat": 33.9430,
      "lon": -118.4090,
      "alt": 35100
    }
  }
}

aircraft:new and aircraft:remove

New Aircraft:

{
  "type": "aircraft:new",
  "data": {
    "hex": "A1B2C3",
    "flight": "UAL456",
    "lat": 34.0522,
    "lon": -118.2437,
    "alt_baro": 5000
  }
}

Remove Aircraft:

{
  "type": "aircraft:remove",
  "data": {
    "hex": "A1B2C3",
    "reason": "timeout"
  }
}

Request Types

Request TypeParametersDescription
aircrafticaoGet single aircraft by ICAO
aircraft_listmilitary_only, category, min_altitude, max_altitudeGet filtered aircraft list
aircraft-infoicaoGet detailed aircraft info
aircraft-info-bulkicaos: string[]Get info for multiple aircraft
aircraft-statsNoneGet live statistics
photoicao, thumbnailGet aircraft photo URL
sightingshours, limit, offset, icao_hex, callsignGet historical sightings
antenna-polarhoursGet antenna polar coverage
antenna-rssihours, sample_sizeGet RSSI vs distance data

Safety Consumer

Endpoint: /ws/safety/

Real-time safety event monitoring including TCAS alerts, emergency squawks, and conflict detection.

Topics

TopicBadgeDescription
eventseventsAll safety events
tcastcasTCAS-specific events
emergencyemergencyEmergency squawk events
allallAll safety data

Event Severity Levels

SeverityIndicatorDescription
criticalRedImmediate attention required (e.g., 7700 squawk)
highOrangeSignificant event (e.g., TCAS RA)
mediumYellowNotable event (e.g., TCAS TA)
lowGreenInformational (e.g., unusual squawk)

Event Types

safety:event

New safety event detected - delivered immediately (bypasses batching).

{
  "type": "safety:event",
  "data": {
    "id": 124,
    "timestamp": "2024-01-15T10:31:00.000Z",
    "event_type": "emergency_squawk",
    "severity": "critical",
    "icao_hex": "A1B2C3",
    "callsign": "N12345",
    "message": "Emergency squawk 7700 detected",
    "details": {
      "squawk": "7700",
      "altitude": 10000,
      "position": { "lat": 34.05, "lon": -118.25 }
    }
  }
}

safety:snapshot

Initial active events on connect.

{
  "type": "safety:snapshot",
  "data": {
    "events": [
      {
        "id": 123,
        "timestamp": "2024-01-15T10:30:00.000Z",
        "event_type": "TCAS_RA",
        "severity": "high",
        "icao_hex": "A1B2C3",
        "icao_hex_2": "D4E5F6",
        "callsign": "UAL123",
        "callsign_2": "DAL456",
        "message": "TCAS Resolution Advisory - Climb",
        "acknowledged": false
      }
    ],
    "count": 1,
    "timestamp": "2024-01-15T10:30:00.000Z"
  }
}

Request Types

Request TypeParametersDescription
active_eventsevent_type, severityGet active safety events
event_historyevent_type, icao, limitGet event history
acknowledgeevent_idAcknowledge a safety event
safety-event-detailevent_idGet detailed event info

Alerts Consumer

Endpoint: /ws/alerts/

Custom alert rule triggers with user-specific channels for personalized notifications.

Topics

TopicBadgeDescription
alertsalertsAll alert triggers (public)
triggerstriggersAlert trigger events
allallAll alert data

User-Specific Channels

Authenticated users receive alerts on private channels:

alerts_user_{user_id}      - User's private alerts
alerts_session_{session_key} - Session-based alerts

Event Types

alert:triggered

New alert triggered - delivered immediately.

{
  "type": "alert:triggered",
  "data": {
    "id": 457,
    "rule_id": 12,
    "rule_name": "Low Altitude Alert",
    "icao_hex": "A1B2C3",
    "callsign": "N12345",
    "message": "Aircraft below 1000ft detected",
    "priority": "medium",
    "aircraft_data": {
      "hex": "A1B2C3",
      "alt_baro": 800,
      "lat": 34.05,
      "lon": -118.25
    },
    "triggered_at": "2024-01-15T10:31:00.000Z"
  }
}

Request Types

Request TypeParametersDescription
alertshours, limitGet alert history
alert-rulesNoneGet active alert rules
acknowledge-alertidAcknowledge single alert
acknowledge-all-alertsNoneAcknowledge all alerts
my-subscriptionsNoneGet user's rule subscriptions

ACARS Consumer

Endpoint: /ws/acars/

ACARS/VDL2 datalink message streaming with frequency and label filtering.

Topics

TopicBadgeDescription
messagesmessagesAll ACARS messages
vdlm2vdlm2VDL Mode 2 messages only
allallAll ACARS data

Event Types

acars:message

New ACARS message received.

{
  "type": "acars:message",
  "data": {
    "id": 790,
    "timestamp": "2024-01-15T10:31:00.000Z",
    "source": "ACARS",
    "channel": 3,
    "frequency": "131.550",
    "icao_hex": "A1B2C3",
    "registration": "N12345",
    "callsign": "UAL123",
    "label": "SQ",
    "block_id": "A",
    "msg_num": "001",
    "text": "REQUEST OCEANIC CLEARANCE",
    "decoded": {
      "message_type": "clearance_request",
      "route": "NATU TRACK A"
    },
    "signal_level": -42.5
  }
}

Request Types

Request TypeParametersDescription
messagesicao, callsign, label, source, frequency, hours, limitGet filtered messages
statsNoneGet ACARS statistics
labelsNoneGet label reference data

Stats Consumer

Endpoint: /ws/stats/

Real-time statistics and analytics streaming with subscription-based updates.

Message Format

The stats consumer uses a different message format with type prefixes:

sequenceDiagram
    participant C as Client
    participant S as Stats Server

    C->>S: {"type": "stats.subscribe", "stat_types": ["flight_patterns"]}
    S-->>C: {"type": "stats.subscribed", "stat_types": ["flight_patterns"]}

    loop Periodic Updates
        S->>C: {"type": "stats.update", "stat_type": "flight_patterns", "data": {...}}
    end

    C->>S: {"type": "stats.request", "stat_type": "geographic", "request_id": "123"}
    S-->>C: {"type": "stats.response", "request_id": "123", "data": {...}}

Available Stat Types

CategoryStat Types
Flight Patternsflight_patterns, geographic, busiest_hours, common_aircraft_types, countries, airlines, airports
Session Analyticstracking_quality, coverage_gaps, engagement
Time Comparisonweek_comparison, seasonal_trends, day_night, weekend_weekday, daily_totals, weekly_totals, monthly_totals
ACARSacars_stats, acars_trends, acars_airlines, acars_categories
Gamificationpersonal_records, rare_sightings, collection_stats, spotted_by_type, spotted_by_operator, streaks, lifetime_stats
Generalhistory_stats, history_trends, history_top, safety_stats, aircraft_stats

Airspace Consumer

Endpoint: /ws/airspace/

Airspace advisories, boundaries, and aviation weather data.

Topics

TopicBadgeDescription
advisoriesadvisoriesG-AIRMETs, SIGMETs
boundariesboundariesClass B/C/D, MOAs
allallAll airspace data

Request Types

Request TypeParametersDescription
advisorieshazard, advisory_typeGet active advisories
boundariesairspace_class, lat, lon, radius_nmGet airspace boundaries
metarslat, lon, radius_nm, limitGet METAR observations
tafstationGet TAF forecast
pirepslat, lon, radius_nm, hoursGet PIREPs
sigmetshazardGet SIGMETs
airportslat, lon, radius_nm, limitGet nearby airports
navaidslat, lon, radius_nm, type, limitGet navigation aids

NOTAMs Consumer

Endpoint: /ws/notams/

NOTAMs and Temporary Flight Restrictions (TFRs).

Topics

TopicBadgeDescription
notamsnotamsAll NOTAM types
tfrstfrsOnly Temporary Flight Restrictions
allallAll NOTAM updates

Event Types

notams:tfr_new

New TFR alert - critical for flight planning.

{
  "type": "notams:tfr_new",
  "data": {
    "id": 302,
    "notam_id": "1/2346",
    "type": "TFR",
    "location": "KSFO",
    "latitude": 37.6213,
    "longitude": -122.3790,
    "radius_nm": 10,
    "floor_ft": 0,
    "ceiling_ft": 18000,
    "reason": "Stadium Event",
    "effective_start": "2024-01-15T18:00:00.000Z",
    "effective_end": "2024-01-15T23:00:00.000Z"
  }
}

Audio Consumer

Endpoint: /ws/audio/

Radio transcription updates and audio transmission streaming.

Topics

TopicBadgeDescription
transmissionstransmissionsAll audio transmissions
transcriptionstranscriptionsTranscription updates only
allallAll audio data

Event Types

audio:transcription_completed

Transcription finished with identified callsigns.

{
  "type": "audio:transcription_completed",
  "data": {
    "id": 501,
    "transcript": "United four five six heavy, runway two five left, cleared for takeoff",
    "transcript_confidence": 0.95,
    "identified_airframes": ["UAL456"],
    "transcription_completed_at": "2024-01-15T10:30:15.000Z"
  }
}

Cannonball Consumer

Endpoint: /ws/cannonball/

Mobile threat detection mode for real-time overhead tracking. Optimized for battery efficiency and GPS integration.

Message Flow

sequenceDiagram
    participant M as Mobile
    participant S as Server

    M->>S: Connect
    S-->>M: {"type": "session_started", "session_id": "abc123"}

    M->>S: {"type": "position_update", "lat": 34.05, "lon": -118.25}
    S-->>M: {"type": "threats", "data": [...], "count": 3}

    M->>S: {"type": "set_radius", "radius_nm": 15}
    S-->>M: {"type": "radius_updated", "radius_nm": 15}

    loop GPS Updates
        M->>S: Position Update
        S-->>M: Threats Response
    end

Threat Levels

LevelIndicatorDescription
criticalRedImmediate threat - very close, approaching
warningOrangeNearby threat requiring attention
infoGreenDistant or departing aircraft

Trend Values

TrendIndicatorDescription
approachingUpGetting closer (> 0.05nm/update)
holdingRightMaintaining distance
departingDownMoving away (> 0.05nm/update)
unknownUnknownFirst observation

Threat Response

{
  "type": "threats",
  "data": [
    {
      "hex": "A1B2C3",
      "callsign": "N12345",
      "category": "Law Enforcement",
      "description": "Police Helicopter",
      "distance_nm": 2.5,
      "bearing": 45,
      "relative_bearing": 315,
      "direction": "NE",
      "altitude": 1500,
      "ground_speed": 80,
      "trend": "approaching",
      "threat_level": "warning",
      "is_law_enforcement": true,
      "is_helicopter": true,
      "confidence": "high",
      "lat": 34.06,
      "lon": -118.24
    }
  ],
  "count": 1,
  "position": { "lat": 34.05, "lon": -118.25 },
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Connection Lifecycle

Heartbeat Protocol

sequenceDiagram
    participant C as Client
    participant S as Server

    Note over C,S: Every 30 seconds
    C->>S: {"action": "ping"}
    S-->>C: {"type": "pong"}

    Note over C,S: If no pong within 10s
    C->>C: Trigger reconnect

Connection States

StateIndicatorDescription
connectingYellowEstablishing WebSocket connection
connectedGreenConnection established, receiving data
reconnectingOrangeConnection lost, attempting to reconnect
disconnectedRedConnection closed
errorErrorAuthentication or protocol error

Reconnection Strategy

The client uses exponential backoff with jitter for resilient reconnection:

graph LR
    A[Connection Lost] --> B{Attempt #1}
    B -->|1s| C[Reconnect]
    C -->|Fail| D{Attempt #2}
    D -->|2s + jitter| E[Reconnect]
    E -->|Fail| F{Attempt #3}
    F -->|4s + jitter| G[Reconnect]
    G -->|Fail| H{Attempt #N}
    H -->|max 30s| I[Reconnect]

Configuration:

SettingValueDescription
initialDelay1000msStarting delay
maxDelay30000msMaximum delay cap
multiplier2xExponential factor
jitter0-30%Random variance
maxAttemptsInfinityNever give up

Close Codes

CodeStatusMeaningAction
1000OKNormal closureNo reconnect
1001OutGoing away (page unload)No reconnect
4000TimeoutHeartbeat timeoutReconnect
4001LockedUnauthorizedNo reconnect - check auth
OtherWarningUnexpected errorReconnect with backoff

Client Implementation

React Hook Example

import { useState, useEffect, useCallback, useRef } from 'react';

function useSkySpy(endpoint = 'all', topics = ['aircraft']) {
  const [connected, setConnected] = useState(false);
  const [aircraft, setAircraft] = useState([]);
  const wsRef = useRef(null);
  const reconnectAttempt = useRef(0);

  const connect = useCallback(() => {
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const url = `${protocol}//${window.location.host}/ws/${endpoint}/`;

    const ws = new WebSocket(url);
    wsRef.current = ws;

    ws.onopen = () => {
      setConnected(true);
      reconnectAttempt.current = 0;

      // Subscribe to topics
      ws.send(JSON.stringify({
        action: 'subscribe',
        topics: topics
      }));
    };

    ws.onmessage = (event) => {
      const data = JSON.parse(event.data);

      // Handle batch messages
      if (data.type === 'batch') {
        data.messages.forEach(handleMessage);
        return;
      }

      handleMessage(data);
    };

    ws.onclose = (event) => {
      setConnected(false);

      // Reconnect unless normal close or auth failure
      if (event.code !== 1000 && event.code !== 1001 && event.code !== 4001) {
        const delay = Math.min(1000 * Math.pow(2, reconnectAttempt.current), 30000);
        reconnectAttempt.current++;
        setTimeout(connect, delay);
      }
    };
  }, [endpoint, topics]);

  const handleMessage = useCallback((data) => {
    switch (data.type) {
      case 'aircraft:snapshot':
      case 'aircraft:update':
        setAircraft(data.data.aircraft || []);
        break;
      case 'aircraft:new':
        setAircraft(prev => [...prev, data.data]);
        break;
      case 'aircraft:remove':
        setAircraft(prev => prev.filter(a => a.hex !== data.data.hex));
        break;
    }
  }, []);

  useEffect(() => {
    connect();
    return () => {
      if (wsRef.current) {
        wsRef.current.close(1000);
      }
    };
  }, [connect]);

  return { connected, aircraft };
}

Python (asyncio) Example

import asyncio
import json
import websockets

async def skyspy_client():
    uri = "wss://example.com/ws/all/"

    async with websockets.connect(uri) as websocket:
        # Subscribe to topics
        await websocket.send(json.dumps({
            "action": "subscribe",
            "topics": ["aircraft", "safety"]
        }))

        # Listen for messages
        async for message in websocket:
            data = json.loads(message)

            if data["type"] == "batch":
                for msg in data["messages"]:
                    process_message(msg)
            else:
                process_message(data)

def process_message(data):
    msg_type = data.get("type", "")

    if msg_type == "aircraft:snapshot":
        aircraft = data["data"]["aircraft"]
        print(f"Received {len(aircraft)} aircraft")

    elif msg_type == "safety:event":
        event = data["data"]
        print(f"Safety event: {event['event_type']} - {event['message']}")

# Run the client
asyncio.run(skyspy_client())

CLI (websocat) Example

# Using websocat for testing
websocat wss://example.com/ws/all/

# Send subscription
{"action": "subscribe", "topics": ["aircraft"]}

# Send request
{"action": "request", "type": "aircraft-stats", "request_id": "test1", "params": {}}

Rate Limits

Default Rate Limits

TopicMax RateIndicatorDescription
aircraft:update10 HzGreenFull aircraft updates
aircraft:position5 HzGreenPosition-only updates
aircraft:delta10 HzGreenDelta updates
stats:update0.5 HzYellowStatistics updates (2s min)
default5 HzGreenAll other message types

Batching Configuration

SettingDefaultDescription
window_ms200Batch collection window
max_size50Maximum messages per batch
max_bytes1 MBMaximum batch size
immediate_typesalert, safety, emergencyTypes that bypass batching

Warning: Clients exceeding rate limits may be throttled. Design your application to handle reduced update frequencies gracefully.


Error Handling

Error Message Format

{
  "type": "error",
  "message": "Description of the error",
  "request_id": "abc123"
}

Error Reference

ErrorCauseResolution
Invalid JSON formatMalformed JSONCheck JSON syntax
Unknown actionUnsupported action typeUse valid action
Unknown request typeUnsupported requestCheck request type
Missing parameterRequired param missingInclude required params
Permission deniedInsufficient accessCheck authentication
Message too largeExceeds 10MB limitReduce message size
Rate limitedToo many requestsSlow down request rate
Invalid tokenToken expired/invalidRefresh token

Security Considerations

Caution: Always follow these security best practices when implementing WebSocket clients.

PracticePriorityDescription
Use WSSCriticalAlways use TLS in production
Token ExpiryHighJWT tokens expire; implement token refresh
Avoid Query TokensHighUse Sec-WebSocket-Protocol header instead
Topic PermissionsMediumSome topics require specific permissions
Rate LimitingMediumClients exceeding limits may be throttled
Connection CleanupLowClose connections properly on unmount

Troubleshooting

Common Issues

SymptomPossible CauseSolution
4001 close codeAuthentication failedCheck token validity
Frequent disconnectsNetwork instabilityCheck network; increase timeouts
No messages receivedNot subscribedSend subscribe action
Delayed updatesRate limiting activeExpected behavior for RPi mode
Connection refusedServer unavailableCheck server status

Debug Logging

Browser Console:

localStorage.setItem('ws_debug', 'true');

Django Server:

LOGGING = {
    'loggers': {
        'skyspy.channels': {
            'level': 'DEBUG',
        },
    },
}

Need help? Check out our examples repository or join our Discord for community support.