Skip to main content

Installation

Choose your preferred installation method:
Add the script before </body>:
After the script loads, use window.crow() to pass functions and objects:

Find Your Product ID

  1. Go to app.usecrow.ai/deploy
  2. Copy your Product ID

User Identity

Authenticate users for persistent conversations and user-specific actions.
Option A — Auto-refresh (recommended). Pass a function that fetches a JWT. The SDK calls it on mount and re-calls it automatically when the token expires (401):
Option B — Manual. Pass a static token (you handle refresh yourself):
See Identity Verification for backend JWT setup.

Client-Side Tools

Register tools the agent can call. The return value from your handler is sent back to the agent, so it can confirm success or handle errors intelligently. See Client-Side Tools for full setup.
Return meaningful results from your tools. The agent uses these to provide accurate feedback like “Done! I’ve navigated you to Settings” or handle errors gracefully.

Page Context

Give the AI context about the current page so it can perform page-aware actions.

Context Label

Show users what page context the AI is aware of — a small label displayed at the top of the widget. Unlike context (which is invisible data sent to the AI), contextLabel is a visible indicator for the user.

Tool Result Callbacks

React to server-side tool completions — refresh data, show a diff UI, dispatch events, etc.

Tool Renderers

Render custom visuals inline in the chat when a tool completes — data cards, tables, charts, and more. Your renderer receives { result, status } and returns one of:

Data Card

Show key metrics with change indicators:

Table

Display structured data in rows and columns:

Chart (Chart.js, D3, ECharts)

For interactive charts, return an HTMLElement instead of a string. The widget mounts it directly:
Timing: window.crow() must be called after crow-widget.js has loaded. In plain HTML this happens naturally (scripts execute in order). In Next.js, use onLoad:
The widget uses Shadow DOM for CSS isolation. Use inline style attributes — Tailwind classes and external CSS won’t apply inside the widget.

Programmatic Open / Close

Open or close the widget from your own code — useful for onboarding flows, feature tours, or reacting to in-app events.
Works with both the floating widget and the copilot sidebar.
window.crow('open') works from anywhere — event handlers, useEffect, timeouts, or third-party callbacks. No imports needed.

Programmatic Send Message

Open the widget and send a message in one call — perfect for “search bar → chat” handoffs, CTA buttons, or triggering the agent from your own UI.
The widget opens automatically (if collapsed) and the message is sent as if the user typed it. Embed your own input on a landing page and hand off to the Crow agent:
You can also pass a plain string:
Combine with Page Context to give the agent full awareness of the current page when the message is sent.

Quick Q&A

Some users find it more intuitive to read setup instructions in Q&A format. Here’s everything above as quick answers:
Install the SDK and drop in one component:
That’s it. Chat works anonymously out of the box. No provider wrapping needed.
Two steps:
  1. Create a backend endpoint (~15 lines) that reads your existing session and mints a JWT signed with your Crow verification secret. Crow never sees your auth system — the JWT is the bridge.
  2. Pass it as a prop:
The SDK calls this on mount and auto-refreshes when the token expires. No useEffect, no setInterval, no manual calls.This enables: conversation history, personalized responses, and user-specific tool actions.See Identity Verification for the backend JWT setup.
Pass a context object. It’s reactive — when it changes (e.g., user navigates), the AI automatically knows.
This gets injected into the AI’s system prompt so it can perform page-aware actions like “edit this item” without asking which one.
React SDK — use onToolResult and toolRenderers as props:
Script Tag — use window.crow():
Everything is a prop on one component:
No providers, no initializers, no polling.

Troubleshooting