# Vue

> A plugin and composables for Vue 3.3 and newer. One shared identification per app, readonly reactive state, and safe under server rendering.

Last updated: 2026-09-17

`@fingerly/vue` installs the [JavaScript SDK](https://docs.fingerly.io/docs/sdks/javascript) as a Vue plugin. Composables read one shared identification as readonly refs.

## Requirements

- Vue 3.3 or newer.
- A [public key](https://docs.fingerly.io/docs/api-keys) with your site in its allowed origins.

> **Note:** Using Nuxt? Install the [Nuxt module](https://docs.fingerly.io/docs/sdks/nuxt) instead. It registers this plugin and auto-imports the composables.

## Install

```bash npm
npm install @fingerly/vue
```

```bash pnpm
pnpm add @fingerly/vue
```

```bash yarn
yarn add @fingerly/vue
```

## Install the plugin

```ts main.ts
import { createApp } from 'vue'
import { createFingerly } from '@fingerly/vue'
import App from './App.vue'

createApp(App)
  .use(createFingerly({ apiKey: 'fly_pk_us_production_…' }))
  .mount('#app')
```

Installing collects nothing. `createFingerly` accepts `apiKey`, `endpoint`, `endpoints`, `fallbackToDefaultEndpoint`, `submit` and `consent`. Change consent at runtime with `useFingerly().setConsent()`.

## Identify on an action

```vue Checkout.vue
<script setup lang="ts">
import { useIdentify } from '@fingerly/vue'

const props = defineProps<{ orderId: string }>()
const { identify, isLoading, error } = useIdentify({ tag: () => 'checkout:' + props.orderId })

async function onSubmit() {
  const { requestId } = await identify()
  await submitOrder({ orderId: props.orderId, requestId })
}
</script>

<template>
  <form @submit.prevent="onSubmit">
    <button :disabled="isLoading">{{ isLoading ? 'Checking…' : 'Pay now' }}</button>
    <p v-if="error">{{ error.message }}</p>
  </form>
</template>
```

## useIdentify

**Options**

- `immediate` (boolean, default `false`): Identify in `onMounted`.
- `tag` (MaybeRefOrGetter<string | undefined>): The tag to send, read at the moment of submission.

Returns the same state as the [React hook](https://docs.fingerly.io/docs/sdks/react#useidentify), with every field a readonly ref and `isReady` and `isSuspicious` as computed refs, plus `identify({ tag?, force? })` and `refresh({ tag? })`.

A call while an identification is in flight gets that identification, and a finished result is reused until you call `refresh()`. A failure is not cached.

## useVerdict

```vue AutomationNotice.vue
<script setup lang="ts">
import { useVerdict } from '@fingerly/vue'

const { matched, confidence } = useVerdict('automation', { min: 'high' })
</script>

<template>
  <aside v-if="matched">Automated access suspected ({{ confidence }})</aside>
</template>
```

Both arguments accept refs and getters. Verdict names are `incognito`, `shields`, `tor`, `emulator`, `automation` and `farm`.

## Options API

```vue Legacy.vue
<script lang="ts">
export default {
  async mounted() {
    const { requestId } = await this.$fingerly.identify()
  },
}
</script>
```

## Server rendering

`immediate` runs in `onMounted`, which never runs on the server. Calling `identify()` during server rendering rejects with `FingerlyServerError`. In a custom SSR setup, create the plugin per app instance rather than at module scope.
