---
description: "Reads the nearest <WebAgentsProvider>: its tool registry, runtime cursor controls and pathname."
---

# `useWebAgents`

Reads the nearest [`<WebAgentsProvider>`](/docs/reference/react/web-agents-provider): its tool registry, runtime cursor controls and pathname. Reach for it when a component has to change the cursor (spotlight, yield) or list the catalog's tools. `useOptionalWebAgents` does the same but returns `null` outside a provider, for UI that also works without one.

## Import

```ts
import { useOptionalWebAgents, useWebAgents } from "@webmcp-agents/react";
import type { WebAgentsContextValue, WebAgentsVisuals } from "@webmcp-agents/react";
```

## Example

A button that turns the spotlight on at runtime. It sits inside the provider; with `visuals={false}` there is no cursor and `visuals` is `null`.

```tsx title="components/spotlight-button.tsx"
import { useWebAgents } from "@webmcp-agents/react";

import { Button } from "@/components/ui/button";

// Turn the spotlight on while an agent works. Must sit inside
// <WebAgentsProvider>.
export function SpotlightButton() {
  const { visuals } = useWebAgents();

  // The provider has `visuals={false}`: there is no cursor.
  if (!visuals) return null;

  return (
    <Button onClick={() => visuals.setSpotlight({ dim: 0.2 })}>
      Dim the page around the agent
    </Button>
  );
}
```

Where a component must also work without a provider, ask for the optional value:

```tsx
const ctx = useOptionalWebAgents();
ctx?.ensureVisuals(); // the provider installs its cursor lazily
```

## Options

Neither hook takes arguments: they return the nearest provider's value.

## Returns

A `WebAgentsContextValue`. `useWebAgents` throws `"useWebAgents must be used inside <WebAgentsProvider>"` outside a provider; `useOptionalWebAgents` returns `null` there.

| Name | Type | Description |
|---|---|---|
| `registry` | `ToolRegistry` | The registry behind the provider's [`createWebAgents`](/docs/reference/core/create-web-agents): its `tools` catalog, which ids are on. See [`createToolRegistry`](/docs/reference/core/create-tool-registry). |
| `visuals` | `WebAgentsVisuals \| null` | Runtime control of the cursor the provider installed: `setSpotlight(value)` and `setYieldToUser(value)`, each taking a boolean or its options object. `null` with `visuals={false}`. |
| `pathname` | `string` | The pathname tools are matched against: the earlier-form `pathname` prop, else the browser's. |
| `getContext()` | `() => unknown` | The latest earlier-form `context` prop, read when a tool runs. |
| `ensureVisuals()` | `() => void` | Install the cursor now if it is not yet. A tool must register after it to be animated. |

## Notes

- `setSpotlight` and `setYieldToUser` act on the cursor the provider holds at that moment. They do nothing while none is installed.
- The context value changes with the pathname. Code that only needs `getContext` or `ensureVisuals` (both stable) should depend on those, not on the whole value.
- The `spotlight` and `yieldToUser` values in the provider's `visuals` prop are also applied when they change, so a later prop change can overwrite a value set here.

## See also

- [Add the chat](/docs/build/add-the-chat) reads the provider this way; the [devtools](/docs/build/devtools) use core's [`currentAgentVisuals`](/docs/reference/core/current-agent-visuals) instead
- [`WebAgentsProvider`](/docs/reference/react/web-agents-provider)
- [`installAgentVisuals`](/docs/reference/core/install-agent-visuals) (`AgentVisuals`, `SpotlightOptions`, `YieldOptions`)
- [`createToolRegistry`](/docs/reference/core/create-tool-registry)
- [`useEnabledTools`](/docs/reference/react/use-enabled-tools)
