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

# Install HelpAlive: script tag, GTM, and frameworks

> Install HelpAlive via script tag or Google Tag Manager, with examples for React, Vue, Angular, plain HTML, and Content Security Policy setup.

HelpAlive installs entirely in the browser. There's nothing to deploy on your servers. You add one script tag (or one Google Tag Manager tag) and one `identify()` call after login. That's the whole install.

This page covers:

* Where to find your personalized snippet
* Installing via JavaScript script tag
* Installing via Google Tag Manager
* Identifying users and workspaces
* Framework-specific examples (React, Vue, Angular, plain HTML)
* Content Security Policy configuration
* Verifying the integration

## Find your personalized snippet

Your dashboard generates a snippet with your API key already filled in. You can grab it from two places:

* **First-time setup:** the **Setup Guide** modal opens automatically the first time an admin logs in. It walks you through script install, `identify()`, and verification — same three steps as below.
* **Anytime after:** **Settings → Integration & API Key**. The integration health card shows whether your script is connected and surfaces the CSP directives you'll need.

The snippet looks like this:

```html theme={null}
<!-- Paste before </head> -->
<script
  src="https://cdn.helpalive.com/sdk/helpalive.js"
  data-api-key="YOUR_API_KEY"
  async>
</script>
```

`YOUR_API_KEY` is replaced with your project's actual key in the dashboard copy.

## JavaScript script tag

The simplest method. Paste the snippet into the `<head>` of your HTML, just before `</head>`, so it loads on every page.

```html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>My App</title>

    <script
      src="https://cdn.helpalive.com/sdk/helpalive.js"
      data-api-key="YOUR_API_KEY"
      async>
    </script>
  </head>
  <body>
    <!-- your app -->
  </body>
</html>
```

That's the whole install. There's no setup function to call — just paste, deploy, and your script is live.

| Attribute      | Required    | What it does                                                                   |
| -------------- | ----------- | ------------------------------------------------------------------------------ |
| `data-api-key` | Yes         | Your project's API key from **Settings → Integration & API Key**.              |
| `async`        | Recommended | Loads the script asynchronously so it doesn't block your page render.          |
| `data-debug`   | No          | Set to `"true"` to log SDK activity to the browser console (development only). |

## Google Tag Manager

If you already manage scripts through GTM, use this method. It's a two-tag setup — one for the SDK, one for `identify()`.

### 1. The HelpAlive tag

In Google Tag Manager: **Tags → New → Tag Configuration → Custom HTML**. Paste:

```html theme={null}
<script>
(function(){
  var s = document.createElement("script");
  s.src = "https://cdn.helpalive.com/sdk/helpalive.js";
  s.setAttribute("data-api-key", "YOUR_API_KEY");
  s.async = true;
  document.head.appendChild(s);
})();
</script>
```

Set the trigger to **All Pages**.

### 2. The `identify()` tag

Add this to your app code right after the user logs in. It pushes the required identity into the GTM Data Layer so the second tag (below) can forward it to HelpAlive:

```javascript theme={null}
// Add this to your app right after user login
dataLayer.push({
  event:                  "helpalive_identify",
  helpalive_user_id:      user.id,
  helpalive_tenant_id:    tenant.id,
  helpalive_tenant_name:  tenant.name,
  helpalive_display_name: user.name,
  helpalive_email:        user.email,
  helpalive_role:         user.role,
  helpalive_plan:         user.plan,
  helpalive_created_at:   user.createdAt
});
```

Then create a second **Custom HTML** tag in GTM, with this code:

```html theme={null}
<script>
  if (window.HelpAlive) {
    window.HelpAlive.identify({
      userId:      {{helpalive_user_id}},
      tenantId:    {{helpalive_tenant_id}},
      tenantName:  {{helpalive_tenant_name}},
      displayName: {{helpalive_display_name}},
      email:       {{helpalive_email}},
      role:        {{helpalive_role}},
      plan:        {{helpalive_plan}},
      createdAt:   {{helpalive_created_at}}
    });
  }
</script>
```

Set the trigger to **Custom Event → `helpalive_identify`**.

For each `helpalive_*` field, create a **Data Layer Variable** in GTM (Variables → New → Data Layer Variable, version 2). The variable name must match the data layer key exactly.

Click **Submit** in GTM to publish the container, then verify from your HelpAlive dashboard.

<Note>
  GTM can't call JavaScript functions directly from your app. The Data Layer is GTM's standard pattern for passing data into tags — same pattern Mixpanel, Amplitude, and Segment use.
</Note>

## Identify your users and workspaces

`identify()` is the only line of code you write yourself. It tells HelpAlive who the user is and which workspace they belong to, and it's required before any activity is recorded.

```javascript theme={null}
HelpAlive.identify({
  userId:      "user_8x92k",       // required
  tenantId:    "acme-corp",        // required (use "default" if no workspaces)
  tenantName:  "Acme Corp",
  displayName: "Priya Sharma",
  email:       "priya@acme.com",
  role:        "admin",
  plan:        "pro",
  createdAt:   1730000000          // optional — when the user signed up
});
```

| Field         | Required | What it's for                                                                                     |
| ------------- | -------- | ------------------------------------------------------------------------------------------------- |
| `userId`      | Yes      | Your app's stable user ID. Avoid using email if it can change.                                    |
| `tenantId`    | Yes      | Workspace or organization ID. For B2C apps without workspaces, pass `"default"`.                  |
| `tenantName`  | No       | Display name for the workspace. Shown in the dashboard instead of the raw ID.                     |
| `displayName` | No       | Full name (e.g. `firstName + " " + lastName`).                                                    |
| `email`       | No       | User's email — used for display and search.                                                       |
| `role`        | No       | User's role (e.g. `"admin"`, `"editor"`, `"viewer"`). Helps segment behavior by permission level. |
| `plan`        | No       | Subscription tier (e.g. `"free"`, `"pro"`, `"enterprise"`). Enables plan-segmented insights.      |
| `createdAt`   | No       | When the user signed up. Helps the Agent tailor its tone for new vs. seasoned users.              |

See [Identify](/sdk/identify) for full semantics — anonymous sessions, workspace switching mid-session, logout cleanup.

## Framework examples

The pattern is the same everywhere: install the script once on app load, call `identify()` after the user authenticates.

<Tabs>
  <Tab title="HTML">
    ```html theme={null}
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <title>My App</title>

        <script
          src="https://cdn.helpalive.com/sdk/helpalive.js"
          data-api-key="YOUR_API_KEY"
          async>
        </script>
      </head>
      <body>
        <!-- your app -->

        <script>
          // Call after your auth flow resolves
          HelpAlive.identify({
            userId:    "user_8x92k",
            tenantId:  "acme-corp",
            email:     "priya@acme.com",
            plan:      "pro"
          });
        </script>
      </body>
    </html>
    ```
  </Tab>

  <Tab title="React">
    ```jsx theme={null}
    // src/App.jsx
    import { useEffect } from "react";

    export default function App({ user }) {
      // Inject the script once on mount
      useEffect(() => {
        const s = document.createElement("script");
        s.src = "https://cdn.helpalive.com/sdk/helpalive.js";
        s.dataset.apiKey = "YOUR_API_KEY";
        s.async = true;
        document.head.appendChild(s);
      }, []);

      // Identify the user once they're available
      useEffect(() => {
        if (!user) return;
        window.HelpAlive?.identify({
          userId:      user.id,
          tenantId:    user.tenantId ?? "default",
          tenantName:  user.tenantName,
          displayName: user.name,
          email:       user.email,
          role:        user.role,
          plan:        user.plan
        });
      }, [user]);

      return <>{/* your app */}</>;
    }
    ```

    For Next.js, drop the `<script>` tag directly into `app/layout.tsx` (or `_document.tsx` on the pages router) instead of injecting it from `useEffect`.
  </Tab>

  <Tab title="Vue">
    ```javascript theme={null}
    // main.js
    import { createApp } from "vue";
    import App from "./App.vue";

    createApp(App).mount("#app");

    const s = document.createElement("script");
    s.src = "https://cdn.helpalive.com/sdk/helpalive.js";
    s.dataset.apiKey = "YOUR_API_KEY";
    s.async = true;
    document.head.appendChild(s);
    ```

    ```vue theme={null}
    <!-- AuthenticatedLayout.vue -->
    <script setup>
    import { watch } from "vue";

    const props = defineProps(["user"]);

    watch(() => props.user, (user) => {
      if (!user) return;
      window.HelpAlive?.identify({
        userId:      user.id,
        tenantId:    user.tenantId ?? "default",
        displayName: user.name,
        email:       user.email,
        plan:        user.plan
      });
    }, { immediate: true });
    </script>
    ```
  </Tab>

  <Tab title="Angular">
    ```typescript theme={null}
    // src/app/app.component.ts
    import { Component, Input, OnInit } from "@angular/core";

    @Component({ selector: "app-root", templateUrl: "./app.component.html" })
    export class AppComponent implements OnInit {
      @Input() user?: { id: string; tenantId: string; name: string; email: string; plan: string };

      ngOnInit(): void {
        const s = document.createElement("script");
        s.src = "https://cdn.helpalive.com/sdk/helpalive.js";
        s.dataset["apiKey"] = "YOUR_API_KEY";
        s.async = true;
        document.head.appendChild(s);

        if (this.user) {
          (window as any).HelpAlive?.identify({
            userId:      this.user.id,
            tenantId:    this.user.tenantId,
            displayName: this.user.name,
            email:       this.user.email,
            plan:        this.user.plan
          });
        }
      }
    }
    ```
  </Tab>
</Tabs>

## Content Security Policy

If you ship a CSP header, allow the HelpAlive origins:

```
script-src  https://cdn.helpalive.com;
connect-src https://api.helpalive.com;
```

The dashboard surfaces this snippet under the script in **Settings → Integration & API Key** so you can grab the exact directives at any time.

To verify CSP is the issue: open your app, press <kbd>F12</kbd> → **Console**. A red error mentioning `helpalive.js` or `Content Security Policy` means CSP is blocking the script.

## Verifying the integration

Once you've deployed:

1. Visit a few pages in your app while logged in.
2. Open your dashboard's **Setup Guide** (or **Settings → Integration & API Key**).
3. The Verify Connection panel polls every few seconds and shows three checks:

| Check                  | What it means                                         | What to do if it fails                                                                                     |
| ---------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| **Event ingestion**    | Your script loaded; events are arriving.              | If pending after 10 minutes, check CSP and that the build with the snippet is deployed.                    |
| **Identity coverage**  | We're receiving `userId` and `tenantId`.              | If pending, your `identify()` call isn't running. Verify it fires after login on every authenticated page. |
| **Profile enrichment** | Optional fields (`displayName`, `email`) are flowing. | Optional, but improves Agent personalization. Add the fields to your `identify()` call.                    |

Verification typically takes under a minute.

## What gets captured automatically

Once the script and `identify()` call are in place, the SDK auto-captures:

* **Pageviews** — including in-app navigations (single-page apps work out of the box).
* **Clicks** — buttons, links, and other interactive elements.
* **Form events** — `form_start` (first interaction), `form_submit` (submission). Field values are never captured.
* **Rage clicks** — repeated clicks on the same element. A strong frustration signal.
* **DOM errors** — JavaScript exceptions and console errors that happened while the user was active.
* **Scroll depth** — per-page max scroll percentage.

You don't tag events, define funnels, or write per-feature instrumentation. The model is autocapture — the only manual call you ever need is `identify()`.

## Privacy by default

Personal data is removed in the browser before anything is sent, and again on our servers before anything is stored. HelpAlive never captures what users type into inputs, the values inside forms, or any password fields. See [Privacy](/privacy/overview) for the full picture.

## Next steps

<CardGroup cols={2}>
  <Card title="Identify users" icon="user-check" href="/sdk/identify">
    Field reference, anonymous sessions, workspace switching.
  </Card>

  <Card title="Configure consent" icon="shield-check" href="/sdk/consent">
    Pause tracking until your cookie banner returns a decision.
  </Card>

  <Card title="Set up the Agent" icon="sparkles" href="/agent/overview">
    Train the AI assistant on your docs.
  </Card>

  <Card title="Privacy posture" icon="lock" href="/privacy/overview">
    What we capture, what we don't, and where redaction happens.
  </Card>
</CardGroup>
