SDKs
Angular SDK
The @yak-io/angular package provides an Angular-compatible provider for integrating Yak. It exposes getter-based reactive state, a state subscription API, and explicit mount()/destroy() methods for lifecycle control.
Installation
npm install @yak-io/angular @yak-io/javascriptpnpm add @yak-io/angular @yak-io/javascriptyarn add @yak-io/angular @yak-io/javascriptbun add @yak-io/angular @yak-io/javascriptQuick Start
Create a Yak service
Wrap the provider in an Angular service for dependency injection:
// yak.service.ts
import { Injectable, OnDestroy } from "@angular/core";
import { createYakProvider, type YakApi } from "@yak-io/angular";
@Injectable({ providedIn: "root" })
export class YakService implements OnDestroy {
private yak: YakApi;
readonly isOpen: YakApi["isOpen"];
readonly isReady: YakApi["isReady"];
constructor() {
this.yak = createYakProvider({
appId: "your-app-id",
getConfig: async () => {
const res = await fetch("/api/yak");
return res.json();
},
onToolCall: async (name, args) => {
const res = await fetch("/api/yak", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, args }),
});
const data = await res.json();
if (!data.ok) throw new Error(data.error);
return data.result;
},
});
// Expose reactive getters
Object.defineProperty(this, "isOpen", {
get: () => this.yak.isOpen,
});
Object.defineProperty(this, "isReady", {
get: () => this.yak.isReady,
});
}
mount() {
this.yak.mount();
}
ngOnDestroy() {
this.yak.destroy();
}
open() {
this.yak.open();
}
close() {
this.yak.close();
}
openWithPrompt(prompt: string) {
this.yak.openWithPrompt(prompt);
}
subscribeToToolEvents(handler: (event: import("@yak-io/angular").ToolCallEvent) => void) {
return this.yak.subscribeToToolEvents(handler);
}
subscribeToState(handler: (state: { isOpen: boolean; isReady: boolean }) => void) {
return this.yak.subscribeToState(handler);
}
}Mount in your root component
// app.component.ts
import { Component, OnInit, OnDestroy } from "@angular/core";
import { YakService } from "./yak.service";
@Component({
selector: "app-root",
template: `
<router-outlet />
<button (click)="yakService.open()">Open Chat</button>
`,
})
export class AppComponent implements OnInit, OnDestroy {
constructor(public yakService: YakService) {}
ngOnInit() {
this.yakService.mount();
}
ngOnDestroy() {
this.yakService.ngOnDestroy();
}
}Set up server handlers
Use @yak-io/javascript to create the API endpoints on your backend. See the JavaScript SDK for runtime-specific examples (Express, Hono, etc.).
// api/yak.ts
import { createYakHandler } from "@yak-io/javascript/server";
export const { GET, POST } = createYakHandler({
routes: [
{ path: "/", title: "Home" },
{ path: "/products", title: "Products" },
],
});API
createYakProvider
Creates a Yak widget instance with plain getter-based reactive state. Use inside an Angular service or component.
| Option | Type | Required | Description |
|---|---|---|---|
appId | string | Yes | Your Yak application ID |
getConfig | () => Promise<ChatConfig> | ChatConfig | No | Config provider for routes and tools |
onToolCall | (name, args) => Promise<unknown> | No | Handler for tool execution |
theme | Theme | No | Widget styling options |
onRedirect | (path: string) => void | No | Custom navigation handler |
disableRestartButton | boolean | No | Hide the restart button in the header |
trigger | boolean | TriggerButtonConfig | No | Configure the floating trigger button |
Return value (YakApi)
| Property | Type | Description |
|---|---|---|
isOpen | boolean (getter) | Whether the chat panel is currently open |
isReady | boolean (getter) | Whether the widget iframe is ready |
open | () => void | Open the chat panel |
close | () => void | Close the chat panel |
openWithPrompt | (prompt: string) => void | Open and send a specific prompt |
subscribeToToolEvents | (handler) => () => void | Subscribe to tool call events (returns unsubscribe) |
subscribeToState | (handler) => () => void | Subscribe to state changes (returns unsubscribe) |
mount | () => void | Mount the widget DOM — call in ngOnInit |
destroy | () => void | Destroy the widget DOM — call in ngOnDestroy |
Reactive State
Use subscribeToState for reactive updates in Angular templates:
import { Component, OnInit, OnDestroy, signal } from "@angular/core";
import { YakService } from "./yak.service";
@Component({
selector: "app-chat-button",
template: `
<button (click)="yakService.open()">
{{ isOpen() ? "Close Chat" : "Open Chat" }}
</button>
`,
})
export class ChatButtonComponent implements OnInit, OnDestroy {
isOpen = signal(false);
private unsubscribe?: () => void;
constructor(public yakService: YakService) {}
ngOnInit() {
this.unsubscribe = this.yakService.subscribeToState((state) => {
this.isOpen.set(state.isOpen);
});
}
ngOnDestroy() {
this.unsubscribe?.();
}
}Tool Events
Subscribe to tool call completion events for UI synchronization:
import { Component, OnInit, OnDestroy } from "@angular/core";
import { YakService } from "./yak.service";
@Component({
selector: "app-orders",
template: `<!-- order list -->`,
})
export class OrdersComponent implements OnInit, OnDestroy {
private unsubscribe?: () => void;
constructor(private yakService: YakService) {}
ngOnInit() {
this.unsubscribe = this.yakService.subscribeToToolEvents((event) => {
if (event.ok && event.name.startsWith("order.")) {
this.refreshOrders();
}
});
}
ngOnDestroy() {
this.unsubscribe?.();
}
private refreshOrders() {
// re-fetch order data
}
}Router Integration
Pass Angular Router's navigate for client-side navigation:
import { Injectable, OnDestroy } from "@angular/core";
import { Router } from "@angular/router";
import { createYakProvider, type YakApi } from "@yak-io/angular";
@Injectable({ providedIn: "root" })
export class YakService implements OnDestroy {
private yak: YakApi;
constructor(private router: Router) {
this.yak = createYakProvider({
appId: "your-app-id",
onRedirect: (path) => this.router.navigateByUrl(path),
// ...other options
});
}
// ...
}