> ## Documentation Index
> Fetch the complete documentation index at: https://outlit-codex-platform-actions-create-update-cli.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Vue Integration

> First-class Vue 3 support with plugin and composables

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install --save @outlit/browser
  ```

  ```bash pnpm theme={null}
  pnpm add @outlit/browser
  ```

  ```bash yarn theme={null}
  yarn add @outlit/browser
  ```

  ```bash bun theme={null}
  bun add @outlit/browser
  ```
</CodeGroup>

## Quick Start

Install the `OutlitPlugin` in your app's entry point and use composables in components.

<Tabs>
  <Tab title="With Authentication (Recommended)">
    If your app has user authentication, use the `useOutlitUser` composable to automatically sync user identity. This is the recommended approach as it automatically handles login/logout transitions.

    ```typescript theme={null}
    // main.ts
    import { createApp } from 'vue'
    import { OutlitPlugin } from '@outlit/browser/vue'
    import App from './App.vue'

    const app = createApp(App)

    app.use(OutlitPlugin, {
      publicKey: import.meta.env.VITE_OUTLIT_KEY,
      trackPageviews: true,
    })

    app.mount('#app')
    ```

    ```vue theme={null}
    <!-- App.vue -->
    <script setup>
    import { computed } from 'vue'
    import { useOutlitUser } from '@outlit/browser/vue'
    import { useAuthStore } from '@/stores/auth'

    const auth = useAuthStore()

    // Build user identity from your auth state
    const outlitUser = computed(() => {
      if (!auth.user) return null
      return {
        email: auth.user.email,
        userId: auth.user.id,
        traits: {
          name: auth.user.name,
          plan: auth.user.plan
        }
      }
    })

    // Auto-sync user identity with Outlit
    useOutlitUser(outlitUser)
    </script>

    <template>
      <router-view />
    </template>
    ```
  </Tab>

  <Tab title="Anonymous Only">
    For marketing sites without authentication, just install the plugin:

    ```typescript theme={null}
    // main.ts
    import { createApp } from 'vue'
    import { OutlitPlugin } from '@outlit/browser/vue'
    import App from './App.vue'

    const app = createApp(App)

    app.use(OutlitPlugin, {
      publicKey: import.meta.env.VITE_OUTLIT_KEY,
      trackPageviews: true,
    })

    app.mount('#app')
    ```
  </Tab>
</Tabs>

<Tip>
  Set your public key in `.env`:

  ```
  VITE_OUTLIT_KEY=pk_your_public_key_here
  ```
</Tip>

### Using the Composable

Track custom events with the `useOutlit` composable:

```vue theme={null}
<script setup>
import { useOutlit } from '@outlit/browser/vue'

const { track } = useOutlit()

function handlePricingClick() {
  track('pricing_clicked', { plan: 'pro' })
}
</script>

<template>
  <button @click="handlePricingClick">
    View Pricing
  </button>
</template>
```

## Plugin Configuration

### OutlitPlugin

The `OutlitPlugin` initializes tracking and provides context to all components.

```typescript theme={null}
import { OutlitPlugin } from '@outlit/browser/vue'

app.use(OutlitPlugin, {
  publicKey: 'pk_xxx',
  trackPageviews: true,
  trackForms: true,
  trackEngagement: true,
  formFieldDenylist: ['custom_secret_field'],
  flushInterval: 5000,
})
```

### Options

<ParamField path="publicKey" type="string" required>
  Your organization's public key.
</ParamField>

<ParamField path="apiHost" type="string" default="https://app.outlit.ai">
  API endpoint for sending events.
</ParamField>

<ParamField path="trackPageviews" type="boolean" default="true">
  Automatically track pageviews on route changes.
</ParamField>

<ParamField path="trackForms" type="boolean" default="true">
  Automatically capture form submissions.
</ParamField>

<ParamField path="formFieldDenylist" type="string[]">
  Additional field names to exclude from form capture.
</ParamField>

<ParamField path="flushInterval" type="number" default="5000">
  How often to flush queued events (ms).
</ParamField>

<ParamField path="autoTrack" type="boolean" default="true">
  Whether to start tracking automatically. Set to `false` to wait for user consent. Use `enableTracking()` from the `useOutlit` composable after consent.
</ParamField>

<ParamField path="autoIdentify" type="boolean" default="true">
  Automatically identify users when they submit forms containing an email field. Set to `false` to disable and call `identify()` manually.
</ParamField>

<ParamField path="trackEngagement" type="boolean" default="true">
  Track engagement metrics (active time on page).
</ParamField>

<ParamField path="idleTimeout" type="number" default="30000">
  Idle timeout in milliseconds for engagement tracking.
</ParamField>

<ParamField path="trackCalendarEmbeds" type="boolean" default="true">
  Track booking events from calendar embeds (Cal.com, Calendly).
</ParamField>

## User Identity Patterns

The `useOutlitUser` composable is the **recommended** way to handle user identity. It's simpler and more reliable than manual `identify()` calls because:

* **Automatic lifecycle management**: Login/logout transitions are handled automatically
* **Reactive**: Uses Vue's reactivity system to sync with your auth state
* **Cleaner code**: No need for watchers with manual `setUser()` calls

### Pattern 1: With Pinia Store

```vue theme={null}
<!-- App.vue or a top-level component -->
<script setup>
import { computed } from 'vue'
import { useOutlitUser } from '@outlit/browser/vue'
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()

const outlitUser = computed(() => {
  if (!userStore.user) return null
  return {
    email: userStore.user.email,
    userId: userStore.user.id,
    traits: {
      name: userStore.user.name,
      plan: userStore.user.plan
    }
  }
})

// Automatically syncs when userStore.user changes
useOutlitUser(outlitUser)
</script>
```

### Pattern 2: With Composable Auth

```vue theme={null}
<script setup>
import { computed } from 'vue'
import { useOutlitUser } from '@outlit/browser/vue'
import { useAuth } from '@/composables/useAuth'

const { user, isAuthenticated } = useAuth()

const outlitUser = computed(() => {
  if (!isAuthenticated.value || !user.value) return null
  return {
    email: user.value.email,
    userId: user.value.id,
    traits: { name: user.value.name }
  }
})

useOutlitUser(outlitUser)
</script>
```

<Info>
  When the user ref changes (login/logout), `useOutlitUser` automatically calls `setUser()` or `clearUser()` internally. You don't need to call these methods manually.
</Info>

## Composables

### useOutlit

The primary composable for tracking events and identifying users.

```vue theme={null}
<script setup>
import { useOutlit } from '@outlit/browser/vue'

const {
  track,
  identify,
  setUser,
  clearUser,
  user,       // User identity and activation helpers
  customer,   // Customer billing methods: trialing, paid, churned
  getVisitorId,
  isInitialized,
  isTrackingEnabled,
  enableTracking,
  disableTracking,
} = useOutlit()

// Track an event
track('button_clicked', { buttonId: 'cta' })

// Identify the user
identify({ email: 'user@example.com', traits: { plan: 'pro' } })

// User activation
user.activate({ flow: 'onboarding' })

// Customer billing methods (requires account identifier)
customer.paid({
  customerId: 'cust_123', // Your app's account/workspace/customer ID
  properties: { plan: 'pro' }
})

// Get visitor ID (null if tracking not enabled)
const visitorId = getVisitorId()
</script>
```

#### Returns

<ParamField path="track" type="(eventName: string, properties?: object) => void">
  Track a custom event.
</ParamField>

<ParamField path="identify" type="(options: IdentifyOptions) => void">
  Identify the current visitor.
</ParamField>

<ParamField path="setUser" type="(identity: UserIdentity) => void">
  Set the current user identity. Ideal for SPA authentication flows.
</ParamField>

<ParamField path="clearUser" type="() => void">
  Clear the current user identity (on logout).
</ParamField>

<ParamField path="user" type="object">
  User identity and activation namespace:

  * `user.identify(options)` - Identify the user
  * `user.activate(properties?)` - Mark user as activated
</ParamField>

<ParamField path="customer" type="object">
  Customer billing methods namespace. Use `customerId` for public billing calls:

  * `customer.trialing(options)` - Mark account as trialing
  * `customer.paid(options)` - Mark account as paid
  * `customer.churned(options)` - Mark account as churned
</ParamField>

<ParamField path="getVisitorId" type="() => string | null">
  Get the current visitor's ID. Returns `null` if tracking is not enabled.
</ParamField>

<ParamField path="isTrackingEnabled" type="Ref<boolean>">
  Whether tracking is currently enabled. Will be `false` if `autoTrack` is `false` and `enableTracking()` hasn't been called.
</ParamField>

<ParamField path="enableTracking" type="() => void">
  Enable tracking. Call this after obtaining user consent. Only needed if `autoTrack` is `false`.
</ParamField>

<ParamField path="disableTracking" type="() => void">
  Disable tracking and flush any pending events. Use this when a user declines or revokes consent.
</ParamField>

<ParamField path="isInitialized" type="Ref<boolean>">
  Whether the tracker is ready.
</ParamField>

### useTrack

A convenience composable that returns just the `track` function:

```vue theme={null}
<script setup>
import { useTrack } from '@outlit/browser/vue'

const track = useTrack()
</script>

<template>
  <button @click="track('feature_clicked', { featureId: '123' })">
    Try Feature
  </button>
</template>
```

### useIdentify

A convenience composable that returns just the `identify` function:

```vue theme={null}
<script setup>
import { useIdentify } from '@outlit/browser/vue'

const identify = useIdentify()

async function handleLogin(email, password) {
  const user = await login(email, password)

  identify({
    email: user.email,
    userId: user.id,
    traits: {
      name: user.name,
      plan: user.plan
    }
  })
}
</script>
```

### useOutlitUser

Automatically syncs a reactive user ref with Outlit:

```vue theme={null}
<script setup>
import { ref, computed } from 'vue'
import { useOutlitUser } from '@outlit/browser/vue'

// Your auth state
const currentUser = ref(null)

// Auto-sync with Outlit - handles login/logout automatically
useOutlitUser(currentUser)

// When user logs in
async function onLogin(credentials) {
  const user = await api.login(credentials)
  currentUser.value = {
    email: user.email,
    userId: user.id,
    traits: { name: user.name, plan: user.plan }
  }
}

// When user logs out
function onLogout() {
  currentUser.value = null
}
</script>
```

## Consent Management

If you need to wait for user consent before tracking:

```typescript theme={null}
// main.ts
app.use(OutlitPlugin, {
  publicKey: import.meta.env.VITE_OUTLIT_KEY,
  autoTrack: false, // Don't track until consent
})
```

```vue theme={null}
<!-- CookieBanner.vue -->
<script setup>
import { useOutlit } from '@outlit/browser/vue'

const { enableTracking, disableTracking, isTrackingEnabled } = useOutlit()

function acceptTracking() {
  localStorage.setItem('tracking-consent', 'true')
  enableTracking()
}
</script>

<template>
  <div v-if="!isTrackingEnabled" class="cookie-banner">
    <p>We use cookies to improve your experience.</p>
    <div class="flex gap-2">
      <button @click="acceptTracking" class="btn-primary">
        Accept
      </button>
      <button @click="disableTracking" class="btn-secondary">
        Decline
      </button>
    </div>
  </div>
</template>
```

## Activation

Track user progression through your product lifecycle:

```vue theme={null}
<script setup>
import { useOutlit } from '@outlit/browser/vue'

const { user } = useOutlit()

function handleOnboardingComplete() {
  user.activate({ flow: 'onboarding', step: 'completed' })
}
</script>

<template>
  <button @click="handleOnboardingComplete">
    Complete Setup
  </button>
</template>
```

<Warning>
  `user.activate()` requires the user to be identified first. Use `useOutlitUser()`, `setUser()`, or `identify()` before calling it.
</Warning>

Use `track()` for product activity. Outlit handles engagement and inactivity automatically; see [Customer Journey](/concepts/customer-journey#automatic-engagement-and-inactivity).

<Info>
  Account billing status (`customer.paid`, `customer.churned`, `customer.trialing`) is tracked separately at the account level. If you've connected Stripe, this is handled automatically.
</Info>

## Vue Router Integration

Track pageviews automatically with Vue Router:

```typescript theme={null}
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [...]
})

export default router
```

<Info>
  If you set `trackPageviews: true` during plugin install (default), pageviews are tracked automatically. Vue Router's History API changes are detected by the SDK.
</Info>

## Pinia Integration

Track state changes with Pinia:

```typescript theme={null}
// stores/user.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    user: null as User | null
  }),

  actions: {
    async login(email: string, password: string) {
      const user = await api.login(email, password)
      this.user = user
      // Identity is synced automatically via useOutlitUser()
    },

    logout() {
      this.user = null
      // Identity is cleared automatically via useOutlitUser()
    }
  }
})
```

## TypeScript Support

Full TypeScript support is included:

```typescript theme={null}
import {
  useOutlit,
  useTrack,
  useIdentify,
  useOutlitUser,
  OutlitPlugin,
  type OutlitPluginOptions,
  type UseOutlitReturn,
} from '@outlit/browser/vue'

import type { UserIdentity } from '@outlit/browser'

// Types are inferred
const { track, identify, setUser } = useOutlit()

// User identity type
const user: UserIdentity = {
  email: 'user@example.com',
  userId: 'usr_123',
  traits: { name: 'Jane' }
}
```

## SSR with Nuxt

For Nuxt applications, see the dedicated [Nuxt integration guide](/tracking/browser/nuxt).

## Next Steps

<CardGroup cols={2}>
  <Card title="Nuxt Integration" icon="layer-group" href="/tracking/browser/nuxt">
    Use Outlit with Nuxt 3
  </Card>

  <Card title="Server-Side Tracking" icon="server" href="/tracking/server/nodejs">
    Track events from your backend
  </Card>

  <Card title="Identity Resolution" icon="fingerprint" href="/concepts/identity-resolution">
    Learn how profiles are merged
  </Card>

  <Card title="NPM Package" icon="npm" href="/tracking/browser/npm">
    Full API reference
  </Card>
</CardGroup>
