Nuxt SDK
The @yak-io/nuxt package provides a Nuxt 3-compatible provider for integrating Yak. It uses Vue refs for reactive state and exposes explicit mount()/destroy() methods for client-side lifecycle control via Nuxt plugins.
Installation
npm install @yak-io/nuxt @yak-io/javascriptpnpm add @yak-io/nuxt @yak-io/javascriptyarn add @yak-io/nuxt @yak-io/javascriptbun add @yak-io/nuxt @yak-io/javascriptQuick Start
Create a client-side Nuxt plugin
Create a .client.ts plugin to ensure the widget only runs in the browser:
// plugins/yak.client.ts
import { createYakProvider } from "@yak-io/nuxt";
export default defineNuxtPlugin((nuxtApp) => {
const yak = createYakProvider({
appId: "your-app-id",
getConfig: async () => {
const res = await $fetch("/api/yak");
return res;
},
onToolCall: async (name, args) => {
const res = await $fetch("/api/yak", {
method: "POST",
body: { name, args },
});
if (!res.ok) throw new Error(res.error);
return res.result;
},
});
nuxtApp.hook("app:mounted", () => yak.mount());
// Provide to the app for use in composables
return {
provide: { yak },
};
});Set up server handlers
Use @yak-io/javascript to create the API endpoints. Create a Nitro server route:
// server/api/yak.get.ts
import { createYakHandler } from "@yak-io/javascript/server";
const { GET } = createYakHandler({
routes: [
{ path: "/", title: "Home" },
{ path: "/products", title: "Products" },
],
});
export default defineEventHandler(async (event) => {
const request = toWebRequest(event);
const response = await GET(request);
return response.json();
});// server/api/yak.post.ts
import { createYakHandler } from "@yak-io/javascript/server";
const { POST } = createYakHandler({
// ... same config
});
export default defineEventHandler(async (event) => {
const request = toWebRequest(event);
const response = await POST(request);
return response.json();
});Sourcing pages from a headless CMS instead of hand-listing routes? See the Prismic adapter for a full Nuxt example that drops straight into the Nitro server routes above.
API
createYakProvider
Creates a Yak widget instance with Vue-compatible readonly refs. Unlike the Vue SDK, the Nuxt SDK does not use Vue's provide/inject or lifecycle hooks — you manage the lifecycle explicitly through Nuxt plugins.
| Option | Type | Required | Description |
|---|---|---|---|
appId | string | Yes | Your Yak application ID |
mode | "chat" | "voice" | "both" | No | Which surfaces the trigger exposes. Defaults to "chat". See Voice Mode. |
getConfig | () => Promise<ChatConfig> | ChatConfig | No | Config provider for routes and tools (used by chat and voice) |
onToolCall | (name, args) => Promise<unknown> | No | Handler for tool execution (used by chat and voice) |
theme | Theme | No | Widget styling options |
onRedirect | (path: string) => void | No | Custom navigation handler |
disableRestartButton | boolean | No | Hide the restart button in the header |
disablePageContent | boolean | No | Stop sending any page context (URL, title, and visible text) to the assistant. The widget still works, but it won't be aware of the page the user is on. |
trigger | boolean | TriggerButtonConfig | No | Configure the floating trigger button |
user | { id, hash } | No | Signed end-user identity. Enables conversation persistence and history. Call setUser() to change it after setup (login/logout). |
Privacy: By default Yak shares the current page's URL, title, and visible text with the assistant so it can answer questions about the page the user is viewing. Set disablePageContent to turn this off entirely — the SDK then sends nothing about the page (not even the URL), so the assistant can't answer page-specific questions.
Return value (YakApi)
| Property | Type | Description |
|---|---|---|
isOpen | Readonly<Ref<boolean>> | Whether the chat panel is currently open |
isReady | Readonly<Ref<boolean>> | Whether the widget iframe is ready |
chatLoading | Readonly<Ref<boolean>> | isOpen && !isReady — opening but not yet interactive |
voiceMachine | Readonly<Ref<VoiceMachine>> | Current voice state — see Voice Mode |
voiceLoading | Readonly<Ref<boolean>> | true while the voice session is connecting |
open | () => void | Open the chat panel |
close | () => void | Close the chat panel |
openWithPrompt | (prompt: string) => void | Open and send a specific prompt |
voiceStart | () => Promise<void> | Start a voice session |
voiceStop | () => Promise<void> | Stop the current voice session |
voiceToggle | () => Promise<void> | Start if idle/error, stop if active |
setUser | (user?: { id, hash }) => void | Set or clear the signed end-user identity after setup — call on login/logout |
subscribeToToolEvents | (handler) => () => void | Subscribe to tool call events (returns unsubscribe) |
mount | () => void | Mount the widget DOM — call in app:mounted hook |
destroy | () => void | Destroy the widget DOM |
Using in Components
Access the provider via useNuxtApp():
<script setup lang="ts">
const { $yak } = useNuxtApp();
function openChat() {
$yak.open();
}
</script>
<template>
<button @click="openChat">Open Chat</button>
<p v-if="$yak.isOpen.value">Chat is open</p>
</template>Tool Events
Subscribe to tool call completion events for UI synchronization:
<script setup lang="ts">
const { $yak } = useNuxtApp();
onMounted(() => {
const unsubscribe = $yak.subscribeToToolEvents((event) => {
if (event.ok && event.name.startsWith("order.")) {
refreshNuxtData();
}
});
onUnmounted(unsubscribe);
});
</script>Router Integration
Pass Nuxt's navigateTo for client-side navigation:
// plugins/yak.client.ts
import { createYakProvider } from "@yak-io/nuxt";
export default defineNuxtPlugin(() => {
const yak = createYakProvider({
appId: "your-app-id",
onRedirect: (path) => navigateTo(path),
// ...other options
});
// ...
});The .client.ts suffix ensures the plugin only runs in the browser, making YakEmbed instantiation SSR-safe.