> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bily.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript

> Add Bily to a browser application and track each client-side route once.

Use the SDK in browser applications built with npm. It loads your exact Bily tracking URL, keeps early calls in order, and can be imported safely during server rendering.

## Install Bily

```bash theme={null}
npm install @bilyai/js
```

## Start tracking once

Select your store. Then open **Bily > Settings > Apps > More settings > Install tracking**, choose your framework, and copy the exact `scriptUrl` from the SDK snippet.

```typescript analytics.ts theme={null}
import { init, track } from "@bilyai/js";

const BILY_SCRIPT_URL =
  "https://tracking.example.com/b.js?shop=store.example.com";

init({ scriptUrl: BILY_SCRIPT_URL });

export { track };
```

Import this module once from your browser entry point. This gives the SDK one clear place to start.

```typescript main.ts theme={null}
import "./analytics";
import { startApplication } from "./application";

startApplication();
```

Do not add a separate script tag. For this installation path, `init()` loads the script.

## Track every later route once

The browser script records the initial page view automatically. Save that URL, then run this function only after the router completes a later navigation.

```typescript analytics.ts theme={null}
import { init, track } from "@bilyai/js";

init({
  scriptUrl: "https://tracking.example.com/b.js?shop=store.example.com",
});

let previousUrl = window.location.href;

export function trackCommittedRoute(): void {
  const currentUrl = window.location.href;
  if (currentUrl === previousUrl) return;

  previousUrl = currentUrl;
  track("PageView", {
    sourceUrl: currentUrl,
    pageTitle: document.title,
  });
}
```

Call `trackCommittedRoute()` from your router's after-navigation callback. Do not call it during the initial mount, or you will duplicate the automatic page view.

## Track successful actions

```typescript create-workspace.ts theme={null}
import { track } from "./analytics";

export async function createWorkspace(name: string) {
  const workspace = await saveWorkspace({ name });

  track("workspace_created", {
    workspace_id: workspace.id,
    workspace_name: workspace.name,
  });

  return workspace;
}
```

Send completion events only after the operation succeeds. This keeps attempted actions from looking like completed ones.

<CardGroup cols={2}>
  <Card title="Track custom events" icon="wave-pulse" href="/guides/custom-events" />

  <Card title="SDK method reference" icon="brackets-curly" href="/api-reference/overview" />
</CardGroup>
