velho

EventSub

Webhook helpers and a WebSocket client for Twitch EventSub, with signature verification and session keepalive.

Choose webhook helpers or the WebSocket client depending on your delivery transport. Both approaches keep sessions healthy and verify Twitch signatures.

Webhook handler

import { handleEventSubWebhook } from "velho";
import { z } from "zod";

const cheerSchema = z.object({
  broadcaster_user_id: z.string(),
  is_anonymous: z.boolean(),
  bits: z.number(),
});

export async function twitchWebhookHandler(req, res) {
  const body = await getRawBody(req);
  const result = await handleEventSubWebhook(
    {
      headers: req.headers,
      body,
    },
    {
      secret: process.env.TWITCH_EVENTSUB_SECRET!,
      eventSchema: cheerSchema,
      onNotification: async ({ subscription, event }) => {
        console.log(subscription.type, event.bits);
      },
      onRevocation: ({ subscription }) => {
        console.warn("Revoked:", subscription);
      },
    }
  );

  res.writeHead(result.status, result.headers);
  res.end(result.body);
}
  • Framework agnostic: provide raw headers and request body.
  • Signature verification uses HMAC-SHA256 with constant-time comparison.
  • Automatic response to webhook_callback_verification challenges.

WebSocket client

import { EventSubWebSocketClient } from "velho";

const wsClient = new EventSubWebSocketClient({ autoReconnect: true });
await wsClient.connect();

wsClient.on("connected", (session) => {
  console.log("Session ID", session.id);
});

wsClient.on("notification", ({ subscription, event }) => {
  console.log(subscription.type, event);
});
  • Keeps sessions alive and honors Twitch reconnect instructions.
  • Resets keepalive timers to detect silent disconnects.
  • Pair with the Helix client to create subscriptions using the active session ID.

On this page