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

# Vue

> Install Zenstep in a Vue 3 application — Options API, Composition API, and Nuxt support.

## Installation

Add the snippet to your `index.html`:

```html index.html theme={null}
<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>
    <div id="app"></div>
    <script
      async
      src="https://cdn.getzenstep.com/v1/snippet.js"
      data-zenstep="YOUR_SNIPPET_KEY"
    ></script>
  </body>
</html>
```

***

## Calling identify — Composition API

Create a composable that calls `identify()` when the user is available:

```ts composables/useZenstep.ts theme={null}
import { watch } from "vue";
import { useAuth } from "./useAuth"; // replace with your auth composable

export function useZenstep() {
  const { user } = useAuth();

  watch(
    () => user.value?.id,
    (userId) => {
      if (!userId) return;
      window.zenstep?.identify(userId, {
        email: user.value?.email,
        plan: user.value?.plan,
        role: user.value?.role,
      });
    },
    { immediate: true },
  );
}
```

Use it in your root `App.vue`:

```vue App.vue theme={null}
<script setup lang="ts">
import { useZenstep } from "./composables/useZenstep";

useZenstep();
</script>

<template>
  <RouterView />
</template>
```

***

## Calling identify — Options API

```vue App.vue theme={null}
<script>
export default {
  name: "App",
  computed: {
    currentUser() {
      return this.$store.getters.currentUser; // adjust for your state management
    },
  },
  watch: {
    "currentUser.id": {
      immediate: true,
      handler(userId) {
        if (!userId) return;
        window.zenstep?.identify(userId, {
          email: this.currentUser.email,
          plan: this.currentUser.plan,
        });
      },
    },
  },
};
</script>
```

***

## Nuxt 3

In Nuxt 3, use a plugin to load the snippet and a composable for identify. Add the script via `useHead` in a plugin:

```ts plugins/zenstep.client.ts theme={null}
export default defineNuxtPlugin(() => {
  useHead({
    script: [
      {
        src: "https://cdn.getzenstep.com/v1/snippet.js",
        "data-zenstep": useRuntimeConfig().public.zenstepKey,
        async: true,
        tagPosition: "bodyClose",
      },
    ],
  });
});
```

Add to `nuxt.config.ts`:

```ts nuxt.config.ts theme={null}
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      zenstepKey: process.env.ZENSTEP_KEY,
    },
  },
});
```

For identify, call it inside a `useAuth` watcher in your app's authenticated layout.

***

## TypeScript types

```ts types/global.d.ts theme={null}
interface ZenstepAPI {
  identify: (
    userId: string,
    attributes?: Record<string, string | number | boolean>,
  ) => void;
  track: (event: string, data?: Record<string, unknown>) => void;
}

declare global {
  interface Window {
    zenstep?: ZenstepAPI;
  }
}

export {};
```

***

## SPA navigation

Vue Router navigation is automatically detected by Zenstep. When the route changes, flows are re-evaluated against the new URL. No additional setup required.
