> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usecrow.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Client-Side Tools

> Register tools that run in the user's browser

Client-side tools execute in the browser instead of on a server. You register handlers via `window.crow('registerTools', {...})`, and the agent calls them like any other tool — but the work happens client-side.

## When to Use

Use client-side tools for **browser-only actions**:

* CSV/file downloads
* Page navigation
* DOM manipulation
* Accessing client-side state (stores, localStorage)

Use server-side tools (OpenAPI/MCP) for API calls, database queries, and anything that requires backend access.

***

## Setup

### 1. Register Handlers

In your app code, register functions the widget can call:

```js theme={null}
window.crow('registerTools', {
  exportListToCSV: async ({ fileName }) => {
    // ... build CSV from app state
    downloadCsv(data, fileName || 'export');
    return { status: 'success', rows_exported: data.length };
  }
});
```

### 2. Upload Tool Definitions

On the [Actions](https://app.usecrow.ai/actions) page, upload a JSON definition so the agent knows the tool exists:

```json theme={null}
[{
  "name": "exportListToCSV",
  "description": "Export the current list to a CSV file. Downloads directly to the user's browser.",
  "parameters": {
    "type": "object",
    "properties": {
      "fileName": { "type": "string", "description": "Name for the CSV file" }
    },
    "required": []
  }
}]
```

Good descriptions help the agent decide when to use the tool.

***

## Handler Contract

Each handler receives an `args` object matching the tool's `parameters` schema and must return an object.

| Outcome     | Return value                            |
| ----------- | --------------------------------------- |
| **Success** | `{ status: "success", ...data }`        |
| **Failure** | `{ status: "error", error: "message" }` |

The returned object is sent back to the agent so it can incorporate the result into its response.

***

## Showing a Loading State

For tools that take a few seconds, call `setToolStatus` to show a spinning indicator with a status message inside the widget. Clear it when done.

```js theme={null}
window.crow('registerTools', {
  createAndPopulateList: async ({ listName }) => {
    window.crow('setToolStatus', 'Creating list...');
    await createList(listName);

    window.crow('setToolStatus', 'Adding leads...');
    await addLeads();

    window.crow('setToolStatus', ''); // clear
    return { status: 'success' };
  }
});
```

The status appears above the input box with a spinner while non-empty, and disappears when set to `''`.

***

## How It Works

```mermaid theme={null}
sequenceDiagram
    participant User
    participant Widget as CrowCopilot
    participant Backend as Crow Backend

    User->>Widget: "Export this list as CSV"
    Widget->>Backend: POST /chat/message
    Backend-->>Widget: SSE tool_call (exportListToCSV)
    Note over Widget: Runs registered handler in browser
    Widget->>Backend: Tool result
    Backend-->>Widget: SSE assistant message
    Widget->>User: "Done — exported 142 rows"
```

1. **User asks** — The message is sent to the agent
2. **Agent picks the tool** — Based on the tool definition
3. **Widget runs the handler** — Executes your registered function client-side
4. **Result flows back** — The agent sees the return value and responds

***

<CardGroup cols={2}>
  <Card title="Tool Renderers" icon="paintbrush" href="/tool-renderers">
    Render custom UI for tool results
  </Card>

  <Card title="Embed Widget" icon="code" href="/embed-widget">
    Full installation guide
  </Card>
</CardGroup>
