> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Quickstart: From Agent to chat widget

> Create an Agent, set its prompt, model, and tools, and embed it on your website as a chat widget.

Use this quickstart to create an Agent, configure its prompt, model, and tools, and embed it as a chat widget on your website.

At the end, you have a live chat widget powered by your Agent.

The examples use a website, but you can embed the widget anywhere that supports HTML or React, including a web app, a mobile app webview, an internal tool, or a documentation site.

![Chat widget open on a dark webpage with a welcome message and message composer.](/_fern-img/d9b9339389d67122eca9d67422f1cad94fef235beae23189f5ad88c1f698aeb4.webp)

## Before you begin

Create a Runtype account before you start. Use the [Runtype sign-up page](https://use.runtype.com/sign-up).

Runtype includes platform keys for a curated selection of models, so you can start without adding provider API keys. For more information, see [platform keys](/user-guide/getting-started/platform-keys-vs-byok).

## Create a product

To create a Product with a chat widget, follow these steps:

1. On the **Products** page, click **New product**.

   ![Products page with the New product button highlighted.](/_fern-img/30ae0fa4d4884f3487a8f3d666ee348904a36a8a332da831d30ed2fd03584b6c.webp)

2. In the create panel, select **Chat Widget** as the [Surface](/user-guide/products-surfaces/what-are-surfaces) type.

   ![Create New Product panel with the Chat Widget option highlighted.](/_fern-img/64151cd204d8740bb881b37bde3cd061adcc6a7698800a88b2f153b3ca7f19b6.webp)

3. In **Name**, enter a product name.

4. Select **New Agent**.

5. Click **Create Chat Widget**. The Product editor opens with the **Configure Agent** step ready in the Surface panel.

   ![Product editor showing a Chat Widget Surface and the Configure Agent panel.](/_fern-img/9d50cb22cb1aa05b7b5892fa1752ed32def8ce315756f9bf81d75ec26f394857.webp)

Runtype creates these items:

* A [Product](/user-guide/products-surfaces/what-are-products): a container for your Capabilities and Surfaces.
* An Agent: a Capability that powers the chat widget. Runtype names it after your Product and gives it the default model and a generic system prompt. For example, a Product named `Acme Support` gets an Agent named `Acme Support Agent`.
* A **Chat Widget** Surface: the widget that your users interact with.

The create panel has two other options. **Use Existing** connects an Agent or Flow that you already have instead of creating one. **Skip for now** also creates a default Agent for a chat widget.

A Product groups Capabilities and Surfaces. It can expose the same Agent through a chat widget, an API endpoint, or another Surface. For more information, see [Creating a Product](/user-guide/products-surfaces/creating-a-product).

## Configure the Agent

The **Configure Agent** step sets the Agent's instructions, model, and tools. To configure the Agent, follow these steps:

1. In **System Prompt**, replace the generic prompt with your instructions. The system prompt controls how the Agent responds. The following sample configures an Agent for product support:

   **`System prompt`**

   ```text title="System prompt"
   You are a support assistant for Acme Inc.

   Help customers with questions about our products and services.

   Be friendly and concise. If you don't know the answer, let the
   customer know you'll escalate their question to a human.
   ```

2. In **Model**, select the model that powers your Agent. The list shows the models available to your account.

   ![Model selector showing available AI models.](/_fern-img/ba7d999bf7faa6d145dd65577306e5cb73abf0c673d1414b08831210ab28ee0d.webp)

3. Optional: To let your Agent call external services, click **Tools** and select the tools that you want. The panel lists platform tools, such as Exa for web search and Firecrawl for web page extraction.

   ![Tool Selection panel showing Exa and Firecrawl.](/_fern-img/8c5a3e5d9b78bb4ba37e97c5fc2520579ef2727fd47744d0473e760f6deeec49.webp)

4. Click **Save & Continue**. The **Style Widget** step opens.

   ![Product editor with the Save & Continue button in the Surface panel.](/_fern-img/b316f89a6ef1ee0fe27cf447cd2c02e5ead28c6dc1719fdb7df63e2fa2a8f442.webp)

For the providers that platform keys cover, see [Available AI models](/user-guide/settings/available-ai-models). For the full list of platform tools, see [Built-in tools](/user-guide/tools/built-in-tools).

## Style your widget

Choose a theme preset or open **Advanced Style Editor** to change colors, fonts, and layout.

Use the theme generator in **Advanced Style Editor** to create a custom theme. Choose one of these sources:

* **From a website URL**: Enter your website URL. Runtype analyzes the site and uses its colors and design patterns to generate a theme.
* **From a description**: Enter a plain-language description, such as `dark mode with purple accents`. You can also attach reference images.

The editor previews the widget in collapsed, expanded, and fullscreen modes.

![Style Widget panel showing the live preview and theme presets.](/_fern-img/e12635e0495d00aea69d8add43ab61c676fc472b7b93f9558e7dadb6cd4b4e4a.webp)

To keep the default theme, click **Skip for now**. To save your changes and continue, click **Continue**. The **Ship** step opens.

## Embed the widget on your site

The **Ship** step shows the embed code for your widget. It reuses an active client token that already covers your Agent, or it creates one. The client token authenticates the widget and limits requests to the Capabilities attached to this Surface. Creating the token also activates the Product and the Surface.

![Ship step showing the Script Tag embed code and the Client Token section.](/_fern-img/21f170ee0aba301b30aedb1b0ed05125842a8af635438cd04320d547543f469b.webp)

The embed code already contains your client token and the style from the **Style Widget** step. Paste it unchanged. To embed the widget, follow these steps:

1. Select the tab for your site:
   * **Script Tag**: for any HTML page.
   * **React**: for a React or bundler app. Install the widget package first with `npm install @runtypelabs/persona`.
2. Copy the embed code. It already turns on the V5 defaults (`future: { v5Defaults: true }`).
3. Paste the code into your site. For a script tag, paste it before the closing `</body>` tag. With the V5 defaults, the launcher appears in the bottom-right corner of your site as a round button.
4. Select the **I've added this to my app** checkbox.
5. Click **Complete Setup**.

To find the embed code later, open the Surface and select the **Ship** tab.

The token that the **Ship** step creates is a live token that accepts requests from any origin (`*`). This lets you test the widget on any site, including `localhost`. Before production, replace `*` with your site's origins. For more information, see [Set allowed origins](/user-guide/products-surfaces/client-tokens-and-domain-restrictions#set-allowed-origins).

![Chat widget open on a dark webpage after embedding.](/_fern-img/d9b9339389d67122eca9d67422f1cad94fef235beae23189f5ad88c1f698aeb4.webp)

## Test the widget

To test the widget, send a message in the widget on your site. The Agent responds according to the system prompt.

To test from the dashboard instead, open the Product editor, open the actions menu on the Chat Widget Surface, and click **Preview**.

![Test chat panel showing a sent message and an Agent response.](/_fern-img/e386712f3bc4a09774272e216ff6d259dd5b5bf527810376e37e072bb707965c.webp)

To change the response, return to the Product editor and open the Agent Capability. Edit the system prompt, model, or tools. To inspect execution details, open [What are Logs?](/user-guide/logs/what-are-logs).

## Troubleshoot the widget

The following problems are the most common when you embed a widget for the first time:

* **The request fails with `Origin not allowed`**: Your site's origin is not in the token's allowed origins, or not in the Surface's allowed origins. Add the exact origin, including the scheme and port, to the token. If the Surface has its own allowed origins, add the origin there too.
* **The request fails with a rate limit or `Session message limit reached`**: A new token accepts 10 requests per minute, 100 per hour, and 100 messages per session. Wait and send the message again, start a new chat session, or raise the limits on the token.
* **The Ship step says that no capabilities are connected**: The Surface has no Agent or Flow. Click **Add Capability**, connect one, and then click **Check Again**.

For more fixes, see [Troubleshoot rejected requests](/user-guide/products-surfaces/client-tokens-and-domain-restrictions#troubleshoot-rejected-requests).

## Build the widget from code

You can build the same widget without the dashboard. Define the Agent in your repository, create or update it with the SDK, create a client token for it, and pass the token and the Agent ID to the widget. This path does not need a Product or a Surface.

Before you run the script, do the following:

* Install the SDK in your project with `npm install @runtypelabs/sdk`.
* Create a Runtype API key. For more information, see [Managing API keys](/user-guide/settings/managing-api-keys).

The following script creates or updates the Agent and its client token:

**`scripts/ensure-widget.mts`**

```typescript title="scripts/ensure-widget.mts"
import { Runtype, defineAgent } from '@runtypelabs/sdk'

Runtype.configure({ apiKey: process.env.RUNTYPE_API_KEY })

const docsAgent = defineAgent({
  name: 'Docs Assistant',
  model: 'claude-sonnet-5',
  systemPrompt: 'Answer questions about our product documentation.',
})

const agent = await Runtype.agents.ensure(docsAgent, {
  deploy: { alias: 'live' },
})
if (agent.result === 'plan') throw new Error('Expected a write, got a plan')

const tokenResult = await Runtype.clientTokens.ensure({
  name: 'Docs site widget',
  agentIds: [agent.agentId],
  allowedOrigins: ['https://docs.example.com'],
})
if (tokenResult.result === 'plan' || !tokenResult.token) {
  throw new Error('No publishable token returned')
}

console.log(
  JSON.stringify({ agentId: agent.agentId, clientToken: tokenResult.token })
)
```

Run the script with your API key:

**`Run the script`**

```bash title="Run the script"
RUNTYPE_API_KEY=YOUR_API_KEY npx tsx scripts/ensure-widget.mts
```

Replace `YOUR_API_KEY` with your Runtype API key. Run the script from your deploy pipeline to keep the Agent and token in sync with your repository.

Each `ensure` call finds the existing Agent or token by name and updates it, so you can run the script on every deploy. `ensure` returns a plan only in dry-run mode, so in a normal run the plan checks narrow the result type for TypeScript. The token check throws if a token with this name already exists and its value can no longer be displayed, such as a live token that you created in the dashboard. In that case, give the token a different name in the script. `deploy: { alias: 'live' }` makes the widget run each new definition. For what happens without it, see [Target a version or release alias](/user-guide/products-surfaces/client-tokens-and-domain-restrictions#target-a-version-or-release-alias). For the token options, see [Create a token from code](/user-guide/products-surfaces/client-tokens-and-domain-restrictions#create-a-token-from-code).

The script creates a live token that accepts requests only from `https://docs.example.com`. To test on your computer, add your local origin, such as `http://localhost:3000`, to `allowedOrigins`.

Pass the two printed values to the widget. With the npm package:

**`Initialize the widget`**

```typescript title="Initialize the widget"
import '@runtypelabs/persona/widget.css'
import { initAgentWidget, markdownPostprocessor } from '@runtypelabs/persona'

initAgentWidget({
  target: 'body',
  config: {
    apiUrl: 'https://api.runtype.com',
    clientToken: 'YOUR_CLIENT_TOKEN',
    agentId: 'YOUR_AGENT_ID',
    future: { v5Defaults: true },
    parserType: 'json',
    postprocessMessage: ({ text }) => markdownPostprocessor(text),
  },
})
```

With a script tag, the `data-config` attribute turns on the V5 defaults:

**`Script tag`**

```html title="Script tag"
<script
  src="https://cdn.runtype.com/persona/latest/install.global.js"
  data-runtype-token="YOUR_CLIENT_TOKEN"
  data-agent-id="YOUR_AGENT_ID"
  data-config='{"future":{"v5Defaults":true}}'
></script>
```

Replace the following:

* `YOUR_CLIENT_TOKEN`: the `clientToken` value that the script prints.
* `YOUR_AGENT_ID`: the `agentId` value that the script prints.

The client token is public, so you can commit it to your site's configuration. The API key stays in your deploy pipeline.

## Next steps

Use these links to continue customizing and evaluating your widget:

* [Creating and configuring Agents](/user-guide/agents/creating-and-configuring-agents): add tools and capabilities to your Agent
* [Embedding the chat widget (script tag)](/user-guide/products-surfaces/embedding-the-chat-widget-script-tag): configure the script tag installer
* [Embedding the chat widget (React)](/user-guide/products-surfaces/embedding-the-chat-widget-react): add the widget to a React app
* [Runtime tools](/developer-guides/guides/runtime-tools): extend the widget with server-side and browser tools
* [Conversation history in an embedded widget](/developer-guides/guides/client-conversation-history): keep conversations across page loads
* [Client tokens and domain restrictions](/user-guide/products-surfaces/client-tokens-and-domain-restrictions): restrict the widget to approved origins
* [Widget theming and customization](/user-guide/products-surfaces/widget-theming-and-customization): refine the widget's appearance and behavior
* [Running an Eval](/user-guide/evals/running-an-eval): compare prompts and models against test data