Quickstart

Connect a browser, listen on a channel, and publish to it from your backend. It takes about five minutes.

1. Get an app

; the dashboard is being rebuilt, so for now we set them up by hand. You get two values:

  • an app id, which is public and goes in your frontend code;
  • an app secret, which stays on your server. It publishes messages and signs presence joins.

2. Install the client

terminal
npm install @pikoman/ws

The package ships TypeScript types and works in any bundler. It opens one WebSocket and shares it between all your channels.

3. Connect and listen

app.ts
import Pikoman from "@pikoman/ws";

const pikoman = new Pikoman("your-app-id");

const channel = pikoman.listen("main-channel");

channel.on("latest-notification", (data) => {
  console.log(data.message);
});

listen can be called before the connection is open; the client joins the channel as soon as it can. Calling it again with the same name returns the same channel. Payloads that are valid JSON arrive parsed, anything else arrives as a string.

4. Publish from your backend

Send a POST to /{channel}/{event} with the app id and secret as basic auth. The body is the payload.

terminal
curl -X POST https://api.pikoman.se/main-channel/latest-notification \
  -u your-app-id:your-app-secret \
  -d '{"message": "hello world"}'

The response tells you how many connected clients received it:

JSON
{ "clients": 1 }

That is the whole loop. The notifications demo runs exactly this.

Connection state

The client reconnects by itself five seconds after a drop and rejoins every channel. It sends a ping after 6.5 seconds of silence and treats 18.5 seconds without any frame as a lost connection.

TypeScript
pikoman.online(() => setBanner(null));
pikoman.offline(() => setBanner("Reconnecting…"));

pikoman.isConnected(); // true once the server has assigned a connection id
pikoman.getClientId(); // that id, as a string

A reconnect is a new connection with a new id. Messages published while a client was away are not replayed, so fetch the current state from your own API after online fires if you need it. The poll demo shows the pattern.

Stop listening

TypeScript
channel.off("latest-notification", handler); // remove one handler

pikoman.leaveChannel("main-channel"); // unsubscribe from the channel

Client reference

new Pikoman(appId, options?)
Member What it does
options.ws_address WebSocket endpoint. Defaults to wss://ws.pikoman.se.
options.auth_url Your endpoint that signs presence joins. Only needed for presence channels.
listen(name) Join a public channel. Returns a Channel.
listenPresence(name, authenticator?) Join a presence channel. The name must start with presence-.
leaveChannel(name) Leave a channel and drop its handlers.
online(fn), offline(fn) Called when the connection is established or lost.
channel.on(event, fn) Handle one event. fn(data) for server messages.
channel.off(event, fn) Remove a handler added with on.
channel.serverMessage(fn) Receive every server message on the channel as the raw event:payload string.

A working starter

pikomanse/example is a small SolidJS and Vite app that listens on main-channel and shows the latest message. Clone it, put your app id in .env.local, and publish to it with the curl command above.

Next: presence channels

We are rebuilding the dashboard

Self-service sign-up is closed while we do. Until the new dashboard is ready we set up apps by hand: write to us with a line about what you are building, and we will send you an app id and a secret.

Write to hello@pikoman.se