Skip to main content
Choose a server-side Socket.IO client that supports Engine.IO v4, WebSocket-only transport, a custom transport path, and an Authorization handshake header. A raw WebSocket client or a Socket.IO server library is not a substitute. Set PHOTON_PROJECT_ID and PHOTON_API_KEY in the process environment. The key needs project:read access to that project. Keep it on the server. PHOTON_API_ORIGIN is optional and defaults to https://api.photon.codes. Every example subscribes again on each connection with the last processed startSeq. A value of 0 starts with new events; a positive value resumes after that cursor. Do not add one. See Cursors and replay.

Node.js

Install socket.io-client (tested with 4.8.3):
This example keeps a cursor in memory. For restart recovery, load it from durable storage before connecting and persist it after each successful handler.
The queue bounds pending handlers. If it fills, the connection restarts and unprocessed deliveries replay from the saved cursor. Socket.IO owns reconnection; do not add a second retry loop. This example does not send synchronous replies; see Reply to a webhook event.

Checkpointed examples

The examples below keep up to 128 deliveries in a queue and process one at a time. They retain queued work across reconnects and skip replayed sequences before queueing them again, including the event being processed. The in-memory last_queued / lastQueued value tracks accepted deliveries; only the processed cursor is saved or sent in a subscription. Replace handle_event, handleEvent, or HandleEvent with your idempotent application handler. They save photon-cursor only after that handler succeeds, and read it before connecting. Do not launch concurrent work from the handler and return before it finishes. Use a separate working directory and cursor file for each project and consumer, with only one process writing that file. The temporary-file rename avoids a partially written checkpoint on process restart. It is a local demo store, not a transaction with your application database or a guarantee against disk failure. For production, persist the cursor with your application state. Until the first event succeeds, there is no replay checkpoint. Restarting with 0 starts live again; it does not recover events missed before that first checkpoint. A handler or checkpoint failure stops the process before it processes later deliveries. A full queue also exits rather than dropping an event or blocking the client’s heartbeat. Diagnose the failure, then restart the process from the saved cursor. Let the library handle network reconnection; do not add a parallel retry loop. These examples do not send synchronous replies; see Reply to a webhook event.
The Java and .NET client versions below can stall after a server-sent WebSocket close frame. They need Photon’s server-side reconnect fix for prompt recovery during a rollout. Until that fix is deployed in your environment, restart a stalled process with its saved cursor. Test rollout recovery before relying on either client in production.

Python

Use python-socketio 5.18.1 with its asyncio client. The separate worker serializes deliveries; an async event callback alone does not serialize application work.
Save the following as main.py:
main.py
Run it from the directory where its cursor should be stored:

Go

Use the client package zishang520/socket.io/clients/socket/v3, tested at v3.0.6. The server package alone does not connect to Photon. This client exposes path, WebSocket transport selection, and handshake headers.
Save the following as main.go:
main.go
Run it from the directory where its cursor should be stored:

Rust

Use rust_socketio 0.6.0 with the async feature, not the Socket.IO server library socketioxide. Unlike the other clients here, this builder takes the transport path in its URL. Leave the namespace at its default /. In this version, acknowledgement arguments arrive as an array inside Payload::Text, so the subscribe result is values[0][0]. Delivery arguments arrive directly as values[0] (event) and values[1] (metadata). Create a binary crate with cargo new photon-events, then set these dependencies in Cargo.toml:
Save the following as src/main.rs:
src/main.rs
Run it from the directory where its cursor should be stored:

Java

Use socket.io-client-java 2.1.2 and Java 11 or later. Add this dependency to your Maven project:
Save the following as PhotonEvents.java in your Java source directory:
PhotonEvents.java
Run PhotonEvents.main with your project’s Maven or IDE launcher from the directory where its cursor should be stored.

.NET

Use SocketIOClient 4.0.5. This example uses its version 4 callback API and was tested with .NET 10.
Save the following as Program.cs:
Program.cs
Run it from the directory where its cursor should be stored:

Client-specific recovery limits

These are examples, not a shared SDK. Initial connection errors and terminal server disconnects do not have identical retry behavior in every library. Read the connection error, correct the credential or project, and restart when needed. A negative subscribe acknowledgement is also an application error, not a reason to keep advancing the cursor. Rust’s emit_with_ack expires the callback after its timeout without calling it. The .NET example uses the library’s acknowledgement callback without adding an application watchdog. If a subscribe acknowledgement never arrives on an otherwise live connection, stop and restart that process; production workers should monitor subscription readiness. The Go example uses zishang520’s client because it supports Photon’s current protocol and required options. Do not substitute the legacy googollee/go-socket.io client: the tested v1.8.0-rc.1 does not support this endpoint’s Engine.IO v4, WebSocket-only transport, custom path, and header requirements.