# Installation

URL: https://supapulse.app/docs/core/installation

Install @supapulse/core from npm or load it with a script tag, and set it up in Vue, Svelte, Angular or plain JavaScript.

## npm [#npm]

```bash
npm install @supapulse/core
```

```ts title="analytics.ts"
import { Supapulse } from '@supapulse/core';

export const supapulse = new Supapulse();

supapulse.init({
  apiToken: import.meta.env.VITE_SUPAPULSE_TOKEN,
});
```

Import this module once from your entry file and reuse the exported instance. Calling `init()` a second time on the same instance does nothing; creating a second instance sends a second pageview, so don't.

`init()` throws `Browser environment required` when `window` is undefined. In server-rendered apps, call it from code that only runs in the browser.

### TypeScript [#typescript]

Types ship with the package:

```ts
import { Supapulse, type SupapulseConfig, type EventData } from '@supapulse/core';

const config: SupapulseConfig = {
  apiToken: import.meta.env.VITE_SUPAPULSE_TOKEN,
  debug: import.meta.env.DEV,
};
```

## Script tag [#script-tag]

```html
<script
  defer
  src="https://cdn.jsdelivr.net/npm/@supapulse/core@1/dist/browser.js"
  data-token="YOUR_PUBLIC_TOKEN"
></script>
```

The script initializes itself from `data-token`, `data-endpoint` and `data-debug`, and exposes the tracker as `window.supapulse`. There is no command queue: if your code may run before the script, check `window.supapulse` first.

## Frameworks [#frameworks]

The tracker follows the History API, so most routers need nothing beyond `init()`.

### Vue [#vue]

```ts title="src/main.ts"
import { createApp } from 'vue';
import App from './App.vue';
import { supapulse } from './analytics';

const app = createApp(App);
app.config.globalProperties.$supapulse = supapulse;
app.mount('#app');
```

### Svelte and SvelteKit [#svelte-and-sveltekit]

```ts title="src/lib/analytics.ts"
import { Supapulse } from '@supapulse/core';

export const supapulse = new Supapulse();
```

```svelte title="src/routes/+layout.svelte"
<script>
  import { onMount } from 'svelte';
  import { supapulse } from '$lib/analytics';

  onMount(() => {
    supapulse.init({ apiToken: import.meta.env.VITE_SUPAPULSE_TOKEN });
  });
</script>

<slot />
```

### Angular [#angular]

```ts title="src/app/analytics.service.ts"
import { Injectable, PLATFORM_ID, inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Supapulse } from '@supapulse/core';

@Injectable({ providedIn: 'root' })
export class AnalyticsService {
  private supapulse = new Supapulse();

  constructor() {
    if (isPlatformBrowser(inject(PLATFORM_ID))) {
      this.supapulse.init({ apiToken: 'YOUR_PUBLIC_TOKEN' });
    }
  }

  event(name: string, data?: Record<string, unknown>) {
    this.supapulse.event(name, data);
  }
}
```

### React and Next.js [#react-and-nextjs]

Use [`@supapulse/react`](https://supapulse.app/docs/react/installation).

## Security [#security]

- Use the **public** token (`pub_…`) in the browser. The secret token must stay on your server.
- The API only accepts browser requests whose `Origin` matches the site's domain or a subdomain of it, so pages on another domain can't send data with your public token. Requests without an `Origin` or `Referer` header skip this check, so treat the public token as public, not secret.
- With a Content Security Policy, allow `https://cdn.jsdelivr.net` in `script-src` (script tag only) and `https://supapulse.app` in `connect-src`.

## Next steps [#next-steps]

- [Basic usage](https://supapulse.app/docs/core/usage)
- [Configuration](https://supapulse.app/docs/core/configuration)
