---
title: "Open Generative UI"
icon: "lucide/Code"
description: "Let agents generate fully interactive HTML/CSS/JS UIs that stream live into the chat."
---

import { Tabs, Tab } from "fumadocs-ui/components/tabs";
import { Callout } from "fumadocs-ui/components/callout";

## What is this?

Open Generative UI lets the agent generate complete, sandboxed UI on the fly — HTML, CSS, and JavaScript — and stream it live into the chat. The user sees the interface build in real time: styles apply first, then HTML streams in progressively, and finally JavaScript expressions execute one by one.

<Callout type="info">
  **Free course:** See this pattern built end-to-end in [Build Interactive Agents with Generative UI](https://www.deeplearning.ai/short-courses/build-interactive-agents-with-generative-ui/) — a free DeepLearning.AI short course taught by CopilotKit's CEO covering the full Generative UI spectrum (Controlled, Declarative, and Open-Ended).
</Callout>

Key benefits:
- **No predefined components** — the agent creates any UI it needs, on demand
- **Live streaming** — HTML streams into a preview as it's generated
- **CDN libraries** — the generated UI can load external libraries (Chart.js, D3, Three.js, etc.) via `<script>` tags
- **Secure sandboxing** — content runs in an isolated iframe without same-origin access
- **Sandbox functions** — expose host application functions to the sandboxed UI for two-way communication

## Basic setup

Enable Open Generative UI by setting `openGenerativeUI: true` in your runtime configuration. That's it — the middleware handles the rest.

<Steps>
  <Step>
    ### Add the dependencies

    ```npm
    npm install @copilotkit/react-ui @copilotkit/react-core @copilotkit/runtime
    ```
  </Step>
  <Step>
    ### Configure the runtime

    ```typescript title="app/api/copilotkit/route.ts"
    import {
      CopilotRuntime,
      createCopilotEndpoint,
      InMemoryAgentRunner,
    } from "@copilotkit/runtime";
    import { BuiltInAgent } from "@copilotkit/runtime/v2";
    import { handle } from "hono/vercel";

    const agent = new BuiltInAgent({
      model: "openai/gpt-5.4",
      prompt: "You are a helpful assistant.",
    });

    const runtime = new CopilotRuntime({
      agents: { default: agent },
      runner: new InMemoryAgentRunner(),
      // Enable Open Generative UI
      openGenerativeUI: true,
    });

    const app = createCopilotEndpoint({
      runtime,
      basePath: "/api/copilotkit",
    });

    export const GET = handle(app);
    export const POST = handle(app);
    ```

    You can also pass options instead of `true`:

    ```typescript
    openGenerativeUI: {
      instructions: "Always use a dark color scheme.",
    }
    ```

    The `instructions` string is appended to the tool description, letting you customize what the agent generates.
  </Step>
  <Step>
    ### Configure the frontend

    ```tsx title="app/page.tsx"
    "use client";

    import { CopilotKit } from "@copilotkit/react-core/v2";
    import { CopilotChat } from "@copilotkit/react-core/v2";
    import "@copilotkit/react-ui/v2/styles.css";

    export default function Page() {
      return (
        <CopilotKit runtimeUrl="/api/copilotkit">
          <CopilotChat />
        </CopilotKit>
      );
    }
    ```

    No special frontend prop is needed — Open Generative UI rendering is built in.
  </Step>
</Steps>

That's it. Ask the agent to "build a calculator" or "show me a bar chart of sales data" and it will generate and stream the UI live.

## Advanced: Sandbox functions

Sandbox functions let the generated UI call back into your host application. This enables two-way communication — for example, a generated settings panel that can toggle your app's theme, or a product card that adds items to your cart.

### Defining sandbox functions

Pass `sandboxFunctions` to the `openGenerativeUI` prop on `CopilotKit`:

```tsx title="app/page.tsx"
"use client";

import { CopilotKit, CopilotChat } from "@copilotkit/react-core/v2";
import "@copilotkit/react-ui/v2/styles.css";
import { useState } from "react";
import { z } from "zod";

export default function Page() {
  const [theme, setTheme] = useState<"light" | "dark">("light");

  return (
    <CopilotKit
      runtimeUrl="/api/copilotkit"
      openGenerativeUI={{
        sandboxFunctions: [
          {
            name: "setTheme",
            description: "Switch the app theme between light and dark mode.",
            parameters: z.object({
              mode: z.enum(["light", "dark"]).describe("The theme mode to set"),
            }),
            handler: async ({ mode }) => {
              setTheme(mode);
              return `Theme set to ${mode}`;
            },
          },
        ],
      }}
    >
      <CopilotChat />
    </CopilotKit>
  );
}
```

### How sandbox functions work

Each sandbox function has:

| Property | Type | Description |
|---|---|---|
| `name` | `string` | Function name, callable from the sandbox |
| `description` | `string` | Tells the agent what this function does |
| `parameters` | Zod schema | Validates arguments passed from the sandbox |
| `handler` | `(args) => Promise<string>` | Runs in the host app, returns a result string |

Inside the generated UI, the agent calls these functions via:

```javascript
// Inside the sandboxed iframe
const result = await Websandbox.connection.remote.setTheme({ mode: "dark" });
```

The function descriptions are automatically included in the agent's context, so it knows which functions are available and how to use them.

### Use cases

- **Theme toggling** — generated UI controls your app's appearance
- **Cart / state management** — product cards that add items to the host app's state
- **Navigation** — generated UI that triggers route changes in the host app
- **Data fetching** — sandbox calls the host to fetch data the iframe can't access directly (due to same-origin restrictions)

## How streaming works

The agent generates parameters in a specific order optimized for the user experience:

1. **`placeholderMessages`** — shown immediately while generating
2. **`css`** — all styles generated first; the preview starts once CSS is complete
3. **`html`** — streams live into the preview as it's generated
4. **`jsFunctions`** — reusable helper functions injected before expressions
5. **`jsExpressions`** — executed one by one; the user sees each take effect

The middleware parses the tool call arguments incrementally and emits activity events as each parameter completes, so the frontend can show progressive updates.

## Using CDN libraries

The sandboxed iframe can load external libraries from CDNs. Include `<script>` or `<link>` tags in the generated HTML `<head>`:

```html
<head>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
  <canvas id="myChart"></canvas>
</body>
```

Libraries like Chart.js, D3, Three.js, x-data-spreadsheet, and any other CDN-hosted library work out of the box.

## Middleware API

If you prefer to apply the middleware to specific agents rather than globally, use `OpenGenerativeUIMiddleware` directly:

```typescript
import { OpenGenerativeUIMiddleware } from "@copilotkit/runtime";

const agent = new BuiltInAgent({
  model: "openai/gpt-5.4",
  prompt: "You are a helpful assistant.",
}).use(
  new OpenGenerativeUIMiddleware({
    instructions: "Use a modern, minimal design.",
  }),
);
```
