Skip to main content

Vue 3 Integration

Integrate Ozwell into your Vue 3 application with a composable-based approach.

Installation

npm install @ozwell/vue
# or
yarn add @ozwell/vue
# or
pnpm add @ozwell/vue

Quick Start

Register the plugin in your app:

// main.ts
import { createApp } from 'vue';
import { OzwellPlugin } from '@ozwell/vue';
import App from './App.vue';

const app = createApp(App);

app.use(OzwellPlugin, {
apiKey: import.meta.env.VITE_OZWELL_API_KEY,
agentId: import.meta.env.VITE_OZWELL_AGENT_ID,
});

app.mount('#app');

Use the component anywhere:

<template>
<div>
<h1>My App</h1>
<OzwellChat />
</div>
</template>

Option 2: Direct Component Import

<template>
<div>
<h1>My App</h1>
<OzwellChat
:api-key="apiKey"
:agent-id="agentId"
theme="auto"
/>
</div>
</template>

<script setup lang="ts">
import { OzwellChat } from '@ozwell/vue';

const apiKey = import.meta.env.VITE_OZWELL_API_KEY;
const agentId = import.meta.env.VITE_OZWELL_AGENT_ID;
</script>

Component API

<OzwellChat />

<template>
<OzwellChat
:api-key="apiKey"
:agent-id="agentId"
theme="auto"
position="bottom-right"
primary-color="#4f46e5"
width="400px"
height="600px"
:auto-open="false"
greeting="Hello! How can I help?"
placeholder="Type a message..."
:context="context"
@ready="onReady"
@open="onOpen"
@close="onClose"
@user-share="onUserShare"
@error="onError"
/>
</template>

Props

PropTypeDefaultDescription
apiKeystringrequiredScoped API key
agentIdstringrequiredAgent ID
theme'light' | 'dark' | 'auto''auto'Color theme
position'bottom-right' | 'bottom-left''bottom-right'Widget position
primaryColorstring'#4f46e5'Accent color
widthstring'400px'Chat window width
heightstring'600px'Chat window height
autoOpenbooleanfalseOpen on mount
greetingstringAgent defaultInitial message
placeholderstring'Type a message...'Input placeholder
contextRecord<string, unknown>{}Context data for agent

Events

EventPayloadDescription
@readyWidget initialized
@openChat window opened
@closeChat window closed
@user-shareunknownUser explicitly shared data
@errorOzwellErrorError occurred

Privacy Note: There is no @message event. Conversation content is private between the user and Ozwell. The @user-share event only fires when the user explicitly chooses to share data.


Composables

useOzwell()

Access the Ozwell instance programmatically:

<template>
<div>
<button @click="ozwell.open()">Open Chat</button>
<button @click="ozwell.close()">Close Chat</button>
<button @click="sendHello">Send Hello</button>

<OzwellChat :api-key="apiKey" :agent-id="agentId" />
</div>
</template>

<script setup lang="ts">
import { OzwellChat, useOzwell } from '@ozwell/vue';

const apiKey = import.meta.env.VITE_OZWELL_API_KEY;
const agentId = import.meta.env.VITE_OZWELL_AGENT_ID;

const ozwell = useOzwell();

function sendHello() {
ozwell.sendMessage('Hello!');
}
</script>

Composable API

interface UseOzwellReturn {
isReady: Ref<boolean>;
isOpen: Ref<boolean>;
open: () => void;
close: () => void;
toggle: () => void;
sendMessage: (content: string) => void;
setContext: (context: Record<string, unknown>) => void;
}

Examples

With Reactive Context

<template>
<OzwellChat
:api-key="apiKey"
:agent-id="agentId"
:context="context"
/>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useUserStore } from '@/stores/user';
import { OzwellChat } from '@ozwell/vue';

const apiKey = import.meta.env.VITE_OZWELL_API_KEY;
const agentId = import.meta.env.VITE_OZWELL_AGENT_ID;

const route = useRoute();
const userStore = useUserStore();

const context = computed(() => ({
userId: userStore.user?.id,
email: userStore.user?.email,
page: route.path,
timestamp: Date.now(),
}));
</script>

Custom Trigger Button

<template>
<div>
<button
v-if="!ozwell.isOpen.value"
@click="ozwell.open()"
class="chat-trigger"
>
💬 Need help?
</button>

<OzwellChat
:api-key="apiKey"
:agent-id="agentId"
:show-trigger="false"
/>
</div>
</template>

<script setup lang="ts">
import { OzwellChat, useOzwell } from '@ozwell/vue';

const apiKey = import.meta.env.VITE_OZWELL_API_KEY;
const agentId = import.meta.env.VITE_OZWELL_AGENT_ID;

const ozwell = useOzwell();
</script>

<style scoped>
.chat-trigger {
position: fixed;
bottom: 20px;
right: 20px;
padding: 12px 24px;
background: #4f46e5;
color: white;
border: none;
border-radius: 24px;
cursor: pointer;
}
</style>

With Pinia Store

// stores/chat.ts
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useChatStore = defineStore('chat', () => {
const messageCount = ref(0);
const isOpen = ref(false);

function incrementMessages() {
messageCount.value++;
}

function setOpen(value: boolean) {
isOpen.value = value;
}

return { messageCount, isOpen, incrementMessages, setOpen };
});
<template>
<OzwellChat
:api-key="apiKey"
:agent-id="agentId"
@open="chatStore.setOpen(true)"
@close="chatStore.setOpen(false)"
@user-share="handleUserShare"
/>
</template>

<script setup lang="ts">
import { OzwellChat } from '@ozwell/vue';
import { useChatStore } from '@/stores/chat';

const apiKey = import.meta.env.VITE_OZWELL_API_KEY;
const agentId = import.meta.env.VITE_OZWELL_AGENT_ID;

const chatStore = useChatStore();

function handleUserShare(data: unknown) {
// Only fires when user explicitly shares
console.log('User shared:', data);
}
</script>

Route-Based Visibility

<template>
<OzwellChat
v-if="showChat"
:api-key="apiKey"
:agent-id="agentId"
/>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { OzwellChat } from '@ozwell/vue';

const apiKey = import.meta.env.VITE_OZWELL_API_KEY;
const agentId = import.meta.env.VITE_OZWELL_AGENT_ID;

const route = useRoute();

const hiddenRoutes = ['/checkout', '/auth', '/admin'];
const showChat = computed(() =>
!hiddenRoutes.some(r => route.path.startsWith(r))
);
</script>

Nuxt 3

For Nuxt 3, create a plugin:

// plugins/ozwell.client.ts
import { OzwellPlugin } from '@ozwell/vue';

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(OzwellPlugin, {
apiKey: useRuntimeConfig().public.ozwellApiKey,
agentId: useRuntimeConfig().public.ozwellAgentId,
});
});
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
ozwellApiKey: process.env.OZWELL_API_KEY,
ozwellAgentId: process.env.OZWELL_AGENT_ID,
},
},
});

TypeScript

Full TypeScript support included:

import type { 
OzwellChatProps,
Message,
OzwellError,
UseOzwellReturn
} from '@ozwell/vue';

Troubleshooting

Widget Not Appearing

  1. Check that the component is mounted in the DOM
  2. Verify API key and agent ID are correct
  3. Check browser console for errors

Context Not Updating

Ensure context is reactive:

<!-- ✅ Reactive computed -->
<OzwellChat :context="computedContext" />

<!-- ❌ Static object won't update -->
<OzwellChat :context="{ page: route.path }" />

Multiple Instances

Only use one <OzwellChat /> component per page.


Next Steps