> For the complete documentation index, see [llms.txt](https://dnotifier.gitbook.io/product-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dnotifier.gitbook.io/product-docs/platform-guides/browser.md).

# Browser

Use the DNotifier JavaScript SDK in **web browsers** for realtime chat, live notifications, and collaborative UIs. Browsers provide a native `WebSocket` API — you do **not** need the `ws` npm package or `WebSocketImpl`.

## Requirements

| Requirement           | Notes                                                |
| --------------------- | ---------------------------------------------------- |
| Modern browser        | Chrome, Firefox, Safari, Edge with WebSocket support |
| Bundler (recommended) | Vite, webpack, esbuild, Parcel                       |
| DNotifier credentials | `appId` and `secret` — see security section below    |

→ [Install — JavaScript / TypeScript](/product-docs/getting-started/installation/javascript-typescript.md)

***

## Install and import

```bash
npm install @dnotifier-realtime/dnotifier
```

```js
import { DNotifier } from "@dnotifier-realtime/dnotifier";
```

The SDK detects `window.WebSocket` automatically when `WebSocketImpl` is omitted.

***

## Basic WebSocket connection

```js
const notifier = new DNotifier({
  appId: import.meta.env.VITE_DNOTIFIER_APP_ID,
  secret: import.meta.env.VITE_DNOTIFIER_SECRET,
  transport: "ws",
  userId: currentUser.id,
  onConnected: () => setConnectionStatus("online"),
  onMessage: handleIncoming,
  onDisconnected: () => setConnectionStatus("offline"),
});

await notifier.connect();
```

{% hint style="info" %}
In the browser, binary and chunked payloads are handled automatically by the SDK.
{% endhint %}

***

## Security: never ship secrets in production bundles

{% hint style="danger" %}
Your app **secret** grants full access to your DNotifier application. **Do not** embed it in client-side JavaScript that ships to end users.
{% endhint %}

| Approach                      | When to use                                                                                    |
| ----------------------------- | ---------------------------------------------------------------------------------------------- |
| **Backend auth proxy**        | Your server authenticates the user, then issues a short-lived token or proxies DNotifier calls |
| **Separate HTTP backend**     | Browser uses your API; server holds `secret` and calls DNotifier with `transport: "http"`      |
| **Dev-only secret in `.env`** | Local prototyping with Vite `import.meta.env` — acceptable for development only                |

→ [Security best practices](/product-docs/operations/security.md) · [Credentials & environment](/product-docs/getting-started/credentials.md)

***

## Framework integration patterns

### React

Connect after login; disconnect on logout or unmount:

```jsx
import { useEffect, useRef } from "react";
import { DNotifier } from "@dnotifier-realtime/dnotifier";

function useDNotifier(userId, appId, secret) {
  const notifierRef = useRef(null);

  useEffect(() => {
    const notifier = new DNotifier({
      appId,
      secret,
      transport: "ws",
      userId,
      onConnected: () => console.log("Connected"),
      onMessage: (msg) => {
        // dispatch to state, context, or event bus
      },
      onDisconnected: () => {},
    });
    notifierRef.current = notifier;
    notifier.connect().catch(console.error);

    return () => {
      notifier.disconnect();
    };
  }, [userId, appId, secret]);

  return notifierRef;
}
```

{% hint style="warning" %}
Prefer loading credentials from your backend after the user signs in, not from build-time env vars in production.
{% endhint %}

### Vue / Svelte / Angular

Same lifecycle: create the client when the authenticated session starts, call `disconnect()` when the component or page unmounts.

***

## Sending and receiving messages

```js
await notifier.send({
  senderId: currentUser.id,
  receiverId: otherUser.id,
  data: { type: "text", text: "Hello!" },
  saveHistory: true,
});

function handleIncoming(msg) {
  const body = msg.payload.toJSON();
  if (body?.type === "text") {
    appendToChat(msg.metadata.sender, body.text);
  }
}
```

→ [Send & receive text](/product-docs/realtime-communication/send-and-receive/javascript-typescript.md)

***

## AI from the browser

`sendAI`, knowledge-base APIs, and workflows use **HTTP transport**. Options:

1. **Call your backend** — recommended; server uses `transport: "http"` with the secret
2. **Direct SDK HTTP** — only for trusted internal tools, never public production UIs

```js
// Pattern: backend API route proxies sendAI
const response = await fetch("/api/ai", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ message: userInput }),
});
```

→ [Choose your transport](/product-docs/getting-started/choose-transport.md)

***

## Binary and large payloads

Images, audio, and large JSON are chunked automatically over WebSocket. Handle reassembled messages in `onMessage`:

```js
onMessage: (msg) => {
  const body = msg.payload.toJSON();
  if (body?.type === "image") {
    const url = URL.createObjectURL(new Blob([body.content]));
    displayImage(url);
  }
},
```

→ [Large messages & chunking](/product-docs/realtime-communication/chunking.md)

***

## Reconnection

The SDK does not auto-reconnect. Implement backoff in `onDisconnected`:

```js
let reconnectTimer;

onDisconnected: () => {
  clearTimeout(reconnectTimer);
  reconnectTimer = setTimeout(async () => {
    try {
      await notifier.connect();
    } catch (err) {
      console.error("Reconnect failed", err);
    }
  }, 3000);
},
```

→ [Error handling & reconnection](/product-docs/realtime-communication/error-handling.md)

***

## Browser-specific limitations

| Topic               | Detail                                                                                                   |
| ------------------- | -------------------------------------------------------------------------------------------------------- |
| **Background tabs** | Browsers may throttle timers; sockets can idle or close                                                  |
| **Mobile Safari**   | Aggressive background suspension — reconnect on `visibilitychange`                                       |
| **CORS**            | HTTP transport uses standard `fetch`; WebSocket connects to `wss://api.dnotifier.com`                    |
| **Service workers** | WebSocket from a service worker is limited; keep the connection in the main thread or a dedicated worker |

***

## Content Security Policy (CSP)

Allow WebSocket connections to DNotifier:

```http
connect-src 'self' wss://api.dnotifier.com https://api.dnotifier.com;
```

Adjust if you use a custom `url` override.

***

## Flutter Web

Flutter Web apps use the **Dart SDK**, not this JavaScript package. See the [Flutter platform guide](/product-docs/platform-guides/flutter.md).

***

## Next steps

* [Your first connection — JavaScript / TypeScript](/product-docs/getting-started/first-connection/javascript-typescript.md)
* [Node.js platform guide](/product-docs/platform-guides/nodejs.md)
* [Building 1:1 chat](/product-docs/chat/building-one-to-one-chat/javascript-typescript.md)
