# JavaScript / TypeScript SDK

Report errors to BugBoard in three steps: install, copy one setup file, then call it.

> **Source on GitHub:** [github.com/bug-board/bugboard-js](https://github.com/bug-board/bugboard-js)
> Runs on Node 20+, browsers, and edge runtimes with **nothing to install or wire up** (it uses the platform `fetch`). The default path loads no dependencies; opt-in payload encryption lazy-loads a tiny tweetnacl sealed-box binding (`tweetnacl-sealedbox-js`) that ships bundled with the SDK — it loads automatically when you set an encryption key, with nothing extra to install. See [Encrypting sensitive reports](/docs/security/encryption).

## 1. Install

```bash
npm i bugboard
```

## 2. Add the setup file

Create one file that configures a shared client, then import it anywhere. This keeps your
keys in a single place. Pick the tab for where the client runs:

<!-- tabs:Client side,Server side -->

```ts
// utils/bugboard.ts
import { createClient } from 'bugboard';

// In the browser or a mobile app, use a publishable key, sent as a bearer token.
export default createClient({
    apiKey: import.meta.env.VITE_BUGBOARD_API_KEY, // bb_pub_…

    // OPTIONAL — if provided, every payload is encrypted before it leaves the client.
    // encryptionKeyId: import.meta.env.VITE_BUGBOARD_ENCRYPTION_KEY_ID,         // bbek_…
    // encryptionPublicKey: import.meta.env.VITE_BUGBOARD_ENCRYPTION_PUBLIC_KEY, // base64 X25519
});
```

```ts
// utils/bugboard.ts
import { createClient } from 'bugboard';

// On a server, use a secret key; requests are HMAC-signed and the secret never leaves the server.
export default createClient({
    keyId: process.env.BUGBOARD_KEY_ID, // bbk_…
    signingSecret: process.env.BUGBOARD_SIGNING_SECRET, // bb_sec_…

    // OPTIONAL — if provided, every payload is encrypted before it leaves the server.
    // encryptionKeyId: process.env.BUGBOARD_ENCRYPTION_KEY_ID,         // bbek_…
    // encryptionPublicKey: process.env.BUGBOARD_ENCRYPTION_PUBLIC_KEY, // base64 X25519

    // OPTIONAL — log reports locally instead of sending them (local debugging / dry run).
    // logLocally: true,
});
```

Set the matching values in your `.env`:

<!-- tabs:Client side,Server side -->

```dotenv
VITE_BUGBOARD_API_KEY=bb_pub_xxxxxxxx
```

```dotenv
BUGBOARD_KEY_ID=bbk_xxxxxxxx
BUGBOARD_SIGNING_SECRET=bb_sec_xxxxxxxx
```

## 3. Use it

Call a severity method with a **title** (required); optionally pass a description — a string or
the caught error — and tags.

```ts
import bugboard from '@/utils/bugboard';

try {
    await payments.charge(order);
} catch (err) {
    bugboard.criticalHigh('Payment failed', err, ['payment', 'backend']);
}
```

The title is all you need:

```ts
bugboard.major('Checkout is slow');
```

That's it — the call returns immediately and the report is delivered in the background.

## Common methods

Most apps only need these four (medium priority); each severity also has `…Low` and `…High`
variants — `criticalHigh`, `minorLow`, and so on:

```ts
bugboard.critical('Payment failed', err); // highest severity
bugboard.major('Checkout is slow', err);
bugboard.moderate('Slow image upload', err);
bugboard.minor('Tooltip misaligned');
```

Tags are an array or a comma-separated string:

```ts
bugboard.critical('Payment failed', err, ['payments', 'checkout']);
bugboard.critical('Payment failed', err, 'payments,checkout');
```

## Serverless / short-lived scripts

Reports deliver in the background, and the SDK flushes automatically on shutdown (Node
`beforeExit`, browser `pagehide`). In environments without lifecycle hooks — lambdas, edge
functions, CLI scripts — flush before returning:

```ts
await bugboard.flush();
```

## Framework guides

The SDK is identical on every runtime — what changes is _where you build the client_, _which
key it uses_, and _where you flush_. These guides cover each one end to end:

| Server                                               | Full-stack                                         | Client                                                        |
| ---------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------- |
| **[Express, Fastify, Koa](/docs/frameworks/node)**   | **[Next.js](/docs/frameworks/nextjs)**             | **[Vite SPA: React, Vue, Svelte](/docs/frameworks/vite-spa)** |
| **[NestJS](/docs/frameworks/nestjs)**                | **[Nuxt](/docs/frameworks/nuxt)**                  |                                                               |
| **[Serverless & edge](/docs/frameworks/serverless)** | **[SvelteKit](/docs/frameworks/sveltekit)**        |                                                               |
|                                                      | **[Remix / React Router](/docs/frameworks/remix)** |                                                               |

In an app with **both** a server and a client bundle, make two modules — one with the secret
key that never reaches the browser, one with the publishable key that does. Adopt whatever
server-only convention your framework enforces (`.server.ts` in SvelteKit and Remix,
`server-only` in Next.js) so an accidental client import fails at build time rather than
shipping your signing secret.

## Next steps

- **[Framework guides](/docs/frameworks)** — detailed integration for every major framework.
- **[API Reference](/docs/api-reference)** — config options, every severity/priority variant
  (`criticalHigh`, …), and the full HTTP contract.
- **[Encrypting sensitive reports](/docs/security/encryption)** — keep the payload out of the
  browser network tab with `encryptionPublicKey` _(the bundled `tweetnacl-sealedbox-js` binding
  auto-loads for you)_.
- **[Source on GitHub](https://github.com/bug-board/bugboard-js)** — the full SDK implementation.
