Chat Integration
JavaScript SDK
The @yak-io/javascript package provides the core SDK and server handlers. It works with any JavaScript runtime that supports the Fetch API.
When to Use
- Building with non-React frameworks (Vue, Svelte, Solid, etc.)
- Need server handlers for custom runtimes (Cloudflare Workers, Deno, Bun)
- Building a custom integration without React components
- Embedding Yak in a vanilla JavaScript application
For React apps, use @yak-io/react. For Next.js, use @yak-io/nextjs.
Installation
npm install @yak-io/javascriptpnpm add @yak-io/javascriptyarn add @yak-io/javascriptbun add @yak-io/javascriptClient SDK
The YakClient class manages iframe communication and is used internally by the React components. For most use cases, we recommend using @yak-io/react or @yak-io/nextjs instead.
import { YakClient } from "@yak-io/javascript";
const client = new YakClient({
appId: "your-app-id",
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;
},
onReady: () => {
console.log("Chat widget ready");
},
onClose: () => {
console.log("Chat closed");
},
});
// Lifecycle methods (typically managed by React components)
client.mount(); // Start listening for messages
client.setWidgetOpen(true); // Open the widget
client.sendPrompt("Help me"); // Send a prompt when ready
client.setWidgetOpen(false); // Close the widget
client.unmount(); // Stop listening and clean upConfiguration Options
| Option | Type | Description |
|---|---|---|
appId | string | Your Yak application ID |
onToolCall | (name, args) => Promise<unknown> | Tool execution handler |
onToolCallComplete | (event: ToolCallEvent) => void | Called after each tool call completes |
onRedirect | (path: string) => void | Navigation handler |
onReady | () => void | Called when iframe is ready |
onClose | () => void | Called when widget is closed |
theme | Theme | Widget theming options |
Cache Invalidation
Use onToolCallComplete to invalidate caches when tools modify data:
const client = new YakClient({
appId: "your-app-id",
onToolCall: async (name, args) => {
// Execute the tool
return executeToolCall(name, args);
},
onToolCallComplete: (event) => {
// Invalidate relevant caches after successful mutations
if (event.ok && event.name.startsWith("order.")) {
queryClient.invalidateQueries({ queryKey: ["orders"] });
}
},
});The ToolCallEvent contains:
| Property | Type | Description |
|---|---|---|
name | string | The tool name that was called |
args | unknown | The arguments passed to the tool |
ok | boolean | Whether the call succeeded |
result | unknown | The result (if ok is true) |
error | string | The error message (if ok is false) |
Server Handlers
The SDK provides Fetch-style handlers for serving routes and executing tools.
import { createYakHandler } from "@yak-io/javascript/server";
const { GET, POST } = createYakHandler({
routes: [
{ path: "/", title: "Home" },
{ path: "/pricing", title: "Pricing" },
],
tools: [
{
id: "custom",
getTools: async () => [
{
name: "greet",
description: "Greet a user by name",
input_schema: {
type: "object",
properties: { name: { type: "string" } },
required: ["name"],
},
},
],
executeTool: async (name, args) => {
if (name === "greet") {
return { message: `Hello, ${args.name}!` };
}
throw new Error(`Unknown tool: ${name}`);
},
},
],
});
export { GET, POST };Route Schema
| Property | Type | Required | Description |
|---|---|---|---|
path | string | ✓ | URL path |
title | string | Human-readable title | |
description | string | Brief description |
Dynamic Route Sources
const cmsRoutes = {
id: "cms",
getRoutes: async () => {
const res = await fetch("https://cms.example.com/api/pages");
return res.json();
},
};
const { GET, POST } = createYakHandler({
routes: [staticRoutes, cmsRoutes],
});Runtime Examples
Cloudflare Workers
import { createYakHandler } from "@yak-io/javascript/server";
const { GET, POST } = createYakHandler({
routes: [{ path: "/", title: "Home" }],
});
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/api/yak") {
if (request.method === "GET") return GET(request);
if (request.method === "POST") return POST(request);
}
return new Response("Not Found", { status: 404 });
},
};Deno
import { createYakHandler } from "@yak-io/javascript/server";
const { GET, POST } = createYakHandler({
routes: [{ path: "/", title: "Home" }],
});
Deno.serve(async (request) => {
const url = new URL(request.url);
if (url.pathname === "/api/yak") {
if (request.method === "GET") return GET(request);
if (request.method === "POST") return POST(request);
}
return new Response("Not Found", { status: 404 });
});Bun
import { createYakHandler } from "@yak-io/javascript/server";
const { GET, POST } = createYakHandler({
routes: [{ path: "/", title: "Home" }],
});
Bun.serve({
port: 3000,
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/api/yak") {
if (request.method === "GET") return GET(request);
if (request.method === "POST") return POST(request);
}
return new Response("Not Found", { status: 404 });
},
});Express / Node.js
import express from "express";
import { createYakHandler } from "@yak-io/javascript/server";
const app = express();
app.use(express.json());
const { GET, POST } = createYakHandler({
routes: [{ path: "/", title: "Home" }],
});
app.all("/api/yak", async (req, res) => {
const url = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
const request = new Request(url, {
method: req.method,
headers: req.headers as HeadersInit,
body: req.method !== "GET" ? JSON.stringify(req.body) : undefined,
});
const response = await (req.method === "POST" ? POST(request) : GET(request));
res.status(response.status);
response.headers.forEach((value, key) => res.setHeader(key, value));
res.send(Buffer.from(await response.arrayBuffer()));
});
app.listen(3000);Hono
import { Hono } from "hono";
import { createYakHandler } from "@yak-io/javascript/server";
const app = new Hono();
const { GET, POST } = createYakHandler({
routes: [{ path: "/", title: "Home" }],
});
app.get("/api/yak", (c) => GET(c.req.raw));
app.post("/api/yak", (c) => POST(c.req.raw));
export default app;TypeScript
Import types for your integrations:
// Client-side types
import type {
YakClientConfig,
Theme,
ThemeColors,
ButtonColors,
ChatConfig,
ChatConfigProvider,
ToolCallHandler,
ToolCallEvent,
ToolCallEventListener,
GraphQLSchemaHandler,
RESTSchemaHandler,
GraphQLRequest,
RESTRequest,
SchemaSource,
GraphQLSchemaSource,
OpenAPISchemaSource,
} from "@yak-io/javascript";
// Server-side types
import type {
RouteInfo,
RouteManifest,
RouteSource,
RouteSourceInput,
ToolDefinition,
ToolManifest,
ToolSource,
ToolSourceInput,
ToolExecutor,
ToolCallPayload,
ToolCallResult,
} from "@yak-io/javascript/server";