npmjs.com ↗
Installnpm install signalbird

signalbird/browser - Browser

React, Vue, Angular, Svelte and plain JavaScript all use the same client. There is no framework-specific wrapper; all you need is one function call.

Why a separate package?

The reason is not technical, it is security.

The server key (sb_secret_live_…) is secret and cannot be embedded in the client: once it reaches a browser it belongs to everyone. The server enforces this as a rule, rejecting a secret key on any request that carries an Origin header (SECRET_KEY_IN_BROWSER).

The browser uses a public key (sb_public_live_…). That key is not secret; its safety comes from restriction:

  • it can write only from the allowed origins (domains) you define in the panel (your domain and its subdomains are added automatically when the key is created),
  • it cannot write the critical level: a critical record from the browser is stored as error (critical breaks quiet hours; a key embedded in the client must not be able to ring the team's phones at night),
  • writing to an unknown channel name opens the channel automatically and silently; there is a cap on automatically opened channels per team.

Client-side code is in everyone's hands. Manage notification rules (who, push or email) in the channel settings; a separate channel for browser errors is recommended.

Install

bash
npm install signalbird

Setup and usage

typescript
import { initSignalbird } from 'signalbird/browser'

const sb = initSignalbird({
  publicKey: 'sb_public_live_…',
  source: 'web',
})

// window.onerror + unhandledrejection
sb.captureErrors('browser')

sb.error('browser', 'the cart could not be updated', { cartId })

Records are not sent one by one but in batches (every 3 seconds by default), and the queue is flushed with sendBeacon as the tab closes: firing dozens of requests per second out of a user's browser is both slow and expensive.

React / Next.js

tsx
'use client'
import { useEffect } from 'react'
import { initSignalbird } from 'signalbird/browser'

export function SignalbirdProvider() {
  useEffect(() => {
    const sb = initSignalbird({
      publicKey: process.env.NEXT_PUBLIC_SIGNALBIRD_DOMAIN_KEY!,
    })
    return sb.captureErrors()
  }, [])

  return null
}

Vue

typescript
import { initSignalbird } from 'signalbird/browser'

const sb = initSignalbird({ publicKey: import.meta.env.VITE_SIGNALBIRD_DOMAIN_KEY })
app.config.errorHandler = (err) => sb.error('browser', String(err))

Angular

typescript
import { ErrorHandler, Injectable } from '@angular/core'
import { initSignalbird } from 'signalbird/browser'

@Injectable()
export class SignalbirdErrorHandler implements ErrorHandler {
  private sb = initSignalbird({ publicKey: environment.signalbirdKey })

  handleError(error: unknown) {
    this.sb.error('browser', String(error))
  }
}

Plain JavaScript

html
<script type="module">
  import { initSignalbird } from 'https://cdn.jsdelivr.net/npm/signalbird/dist/browser.mjs'

  const sb = initSignalbird({ publicKey: 'sb_public_live_…' })
  sb.captureErrors()
</script>

Options

Field Default Description
publicKey - Required. Must start with sb_public_live_
baseUrl https://signalbird.io/api If you run your own installation
source - An origin name added to every record
flushIntervalMs 3000 How often the queue is flushed
maxQueue 50 The most records held in memory

Methods

Method Description
log(key, message, level?, context?) The base call
info · warn · error Level shortcuts
captureErrors(key?) Hooks error + unhandledrejection
flush() Sends the queue right away
destroy() Stops the timer and makes a final send

Version notice

The SDK reports its version on every request: X-Signalbird-Sdk: browser/<version>. When a newer version is released the API responds with Signalbird-Sdk-Status: outdated (or unsupported once it is no longer supported) and the SDK writes a warning once per process (console.warn). The warning is not an error: the request result does not change.

In the panel, Domains → [domain] → Keys shows which SDK version each key is used with; keys on an old version also get a banner at the top of the panel and a notification. To update:

bash
npm i signalbird@latest

Error codes

Code Meaning
ORIGIN_NOT_ALLOWED This domain is not among the key's allowed origins
ORIGIN_REQUIRED A web key cannot be used without an Origin header
DOMAIN_KEY_MISSING · DOMAIN_KEY_INVALID The key is missing, wrong or revoked
DOMAIN_INACTIVE · TEAM_INACTIVE The domain or team is inactive
MODULE_DISABLED Radio is not enabled in your package
AUTO_CHANNEL_LIMIT The cap on automatically opened channels is reached; create the channel in the panel
LIMIT_REACHED Your monthly record limit is full

Chat and push are a separate surface

This page describes the Radio client in the browser (writing logs). Showing live chat to a visitor and registering a push device is a separate surface and uses a separate key (sb_public_live_…):

What you want Where to look
A ready-made chat bubble with no code Widget
My own chat interface (React, Vue, Angular, plain JS) App SDK
Chat in a mobile app App SDK - React Native, Swift, Kotlin
typescript
import { SignalbirdApp } from 'signalbird/app'

const chat = new SignalbirdApp({ publicKey: 'sb_public_live_…' })

await chat.startSession({ name: 'Ayşe' })
await chat.startConversation({ body: 'Where is my parcel?' })

The two clients are independent of each other and work side by side on the same page.