wss://api.socketly.co

Sockets you don’t have to run.

Publish from your server, subscribe from the browser. Presence rosters, signed private channels, per-app quotas and keys you can roll — on an endpoint you never deploy.

two connections opened when this page loaded

Opening two connections…public-lobby-…

clientAda

Connecting…

clientGrace

Connecting…

the wirebytes on arrival

Nothing has crossed yet. Send a message and watch the frame arrive.

Two independent connections; the wire shows Ada's. Sending publishes from this site's server.

0 frames · 0 B

Start freeRead the quickstart

100 connections and 200k messages a day, free. No card.

channels

Three prefixes, and the prefix is the rule.

A channel’s name decides who may join it. There is no second permission model to keep in step with the first — the gateway parses the name.

public-

Open to anyone holding the key

A public key is meant to sit in a browser. Anyone with it can subscribe and read; only your server can write. Right for tickers, build status, anything already on the page.

private-

Your server decides who joins

The client asks your auth endpoint, which signs the subscription with your secret key. The gateway checks that signature before the socket joins the room. You already know who your user is — this is where you say so.

presence-

Private, and it keeps the roster

Everything a private channel does, plus who is here. Members arrive with the subscription, and joins and departures are pushed as they happen. You do not maintain the list.

quickstart

Three steps, and the middle one is conditional.

One install, a public key and a secret key. Both keys are minted the moment you create an app, and the secret is shown exactly once.

  1. 01

    Subscribe in the browser

    The public key belongs here. That is what it is for.

    import { Socketly } from '@socketly/client';
    
    const socketly = new Socketly({
      key: process.env.NEXT_PUBLIC_SOCKETLY_KEY!,
      authEndpoint: '/api/socketly/auth',
    });
    
    socketly
      .subscribe('presence-room-42')
      .bind('new-message', ({ data }) => render(data));
  2. 02

    Authorize, for private and presence channels

    One endpoint, and the only step that asks anything of you. Public channels skip it.

    import { authorizeChannel } from '@socketly/server';
    
    export async function POST(request: Request) {
      const { socket_id, channel_name } = await request.json();
    
      const user = await getCurrentUser();
      if (!user) return new Response('Unauthorized', { status: 401 });
    
      return Response.json(
        await authorizeChannel({
          secret: process.env.SOCKETLY_SECRET!,
          socketId: socket_id,
          channel: channel_name,
          userData: { user_id: user.id, user_info: { name: user.name } },
        }),
      );
    }
  3. 03

    Publish from your server

    The secret key never leaves it.

    import { SocketlyServer } from '@socketly/server';
    
    const socketly = new SocketlyServer({
      secret: process.env.SOCKETLY_SECRET!,
    });
    
    await socketly.trigger('presence-room-42', 'new-message', {
      text: 'Shipped.',
    });

The rest — channels, keys and the React hooks — is in the docs.

agents

Or let your agent do it — and check its own work.

@socketly/mcp gives a coding agent five tools and these docs as a resource. It can publish an event, watch the channel, and see the message arrive — so it finds out whether the code it just wrote works, instead of telling you it does.

claude mcp add socketly \
  --env SOCKETLY_SECRET_KEY=sk_app_… \
  --env SOCKETLY_PUBLIC_KEY=pk_app_… \
  -- npx -y @socketly/mcp
socketly_publish
send an event, as your server would
socketly_subscribe
start watching a channel
socketly_receive
read what has arrived
socketly_channel_info
who is in a presence channel
socketly://docs
these docs, as a resource it reads

Works with Claude Code, Claude Desktop, Cursor, Windsurf and anything else that speaks MCP. How it works.

operations

The part that isn’t the fun part.

Anyone can stand up a Socket.IO server in an afternoon. What takes the time is everything around it, afterwards, forever.

Quotas, by the minute and by the day

Every message passes one chokepoint, so nothing is counted twice and nothing slips past uncounted. When Redis is unreachable we refuse rather than give the product away.

Keys you can roll without an outage

A rolled secret stays valid for a grace window you choose, so servers already deployed keep verifying while you ship the new one. Set the window to zero for a leaked key and the old one dies on the spot.

Origins matched on the host

A public key is public; the origin list on your app is what makes it yours. Matched on the host, port included, with *.example.com when you want subdomains.

Usage you can actually read

Per-minute buckets, zero-filled across the range you asked for. Two busy minutes render as two spikes rather than as a full chart implying sustained load.

plans

Plans

Every number below is read from the constants the gateway enforces, so this page cannot drift from the product.

Plan limits and prices
LimitFree$0/moStarter$19/moPro$49/moScale$199/mo
Messages a day200K1M5M25M
Messages a minute5002K10K50K
Concurrent connections1005002,00010,000
Channels per connection201005002,000
Message size32 KB64 KB128 KB256 KB
Apps210501,000
Usage history7 days30 days90 days365 days

A message counts once when you publish it and once for each connected client we deliver it to, the same way the rest of this category counts. The free plan also includes one workspace.

Start on the free plan

Change plan or cancel from the dashboard.

Your first message is about four minutes away.