Yak Docs
Other Frameworks

Astro

Astro sites use the @yak-io/react package as a React island for the client-side widget and @yak-io/javascript for server handlers.

Installation

npm install @yak-io/react @yak-io/javascript react react-dom
npx astro add react
pnpm add @yak-io/react @yak-io/javascript react react-dom
pnpm astro add react
yarn add @yak-io/react @yak-io/javascript react react-dom
yarn astro add react
bun add @yak-io/react @yak-io/javascript react react-dom
bunx astro add react

Client Component

Create a React component for the Yak widget:

// src/components/YakChat.tsx
import { YakProvider, YakWidget } from "@yak-io/react";

interface YakChatProps {
  appId: string;
}

export function YakChat({ appId }: YakChatProps) {
  return (
    <YakProvider
      appId={appId}
      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;
      }}
      onRedirect={(path) => window.location.href = path}
    >
      <YakWidget />
    </YakProvider>
  );
}

Layout Integration

Add the component to your layout as a React island:

---
// src/layouts/Layout.astro
import { YakChat } from "../components/YakChat";
---

<html>
  <head>
    <title>{title}</title>
  </head>
  <body>
    <slot />
    <YakChat client:load appId={import.meta.env.PUBLIC_YAK_APP_ID} />
  </body>
</html>

The client:load directive ensures the widget loads on the client side immediately. Use client:idle for lower priority loading.

Server Handler

Create an API endpoint for Yak:

// src/pages/api/yak.ts
import type { APIRoute } from "astro";
import { createYakHandler } from "@yak-io/javascript/server";

const { GET: yakGet, POST: yakPost } = createYakHandler({
  routes: [
    { path: "/", title: "Home" },
    { path: "/about", title: "About" },
    { path: "/blog", title: "Blog" },
  ],
});

export const GET: APIRoute = async ({ request }) => {
  return yakGet(request);
};

export const POST: APIRoute = async ({ request }) => {
  return yakPost(request);
};

Dynamic Routes from Content Collections

Pull routes from Astro content collections:

// src/pages/api/yak.ts
import { getCollection } from "astro:content";
import { createYakHandler } from "@yak-io/javascript/server";

async function getRoutes() {
  const posts = await getCollection("blog");
  
  return [
    { path: "/", title: "Home" },
    { path: "/blog", title: "Blog" },
    ...posts.map((post) => ({
      path: `/blog/${post.slug}`,
      title: post.data.title,
      description: post.data.description,
    })),
  ];
}

export const GET: APIRoute = async ({ request }) => {
  const routes = await getRoutes();
  const { GET } = createYakHandler({ routes });
  return GET(request);
};

Adding Tools

Connect to your data sources:

// src/pages/api/yak.ts
const contentTools = {
  id: "content",
  getTools: async () => [
    {
      name: "content.searchPosts",
      description: "Search blog posts by keyword",
      input_schema: {
        type: "object",
        properties: {
          query: { type: "string" },
          limit: { type: "number", default: 5 },
        },
        required: ["query"],
      },
    },
  ],
  executeTool: async (name: string, args: Record<string, unknown>) => {
    if (name === "content.searchPosts") {
      const posts = await getCollection("blog");
      const query = (args.query as string).toLowerCase();
      const limit = (args.limit as number) ?? 5;
      
      return posts
        .filter((post) => 
          post.data.title.toLowerCase().includes(query) ||
          post.body.toLowerCase().includes(query)
        )
        .slice(0, limit)
        .map((post) => ({
          title: post.data.title,
          slug: post.slug,
          description: post.data.description,
        }));
    }
    throw new Error(`Unknown tool: ${name}`);
  },
};

const { GET, POST } = createYakHandler({
  routes: [...],
  tools: [contentTools],
});

Environment Variables

Add your app ID to .env:

PUBLIC_YAK_APP_ID=yak_app_123

Use PUBLIC_ prefix for environment variables that need to be accessible on the client side.

On this page