<!-- AvatarFactory Docs · https://avatarfactory.in/docs/sdk/react-native/app-events · Full map: https://avatarfactory.in/llms.txt -->

# App events

Tell the avatar something happened in your app so it can take a turn about it.

A call does not have to be driven only by speech. `notify()` hands the avatar
something that happened in your app — a screen change, a failed payment, an
abandoned flow — so it can react unprompted, in character.

```tsx
const { notify } = useAvatar();

notify?.({
  name: "checkout.failed",
  data: { reason: "card_declined" },
  policy: "idle_only",
});
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `name` **(required)** | `string` | — | A stable slug matching ^[a-z0-9][a-z0-9_.]{0,63}$ — never prose. This is what the brain is told happened, so free text here would put your app content straight into a turn instruction. |
| `data` | `Record<string, unknown> \| string` | — | Structured detail, serialized and fenced as untrusted reference data. Capped at 512 characters. |
| `policy` | `AppEventPolicy` | `"idle_only"` | When the event is allowed to take a turn. See the table below. |
| `say` | `string` | — | Speak this verbatim and skip the brain. An escape hatch for scripted lines; the brain-mediated form is what keeps the avatar in persona. Capped at 1000 characters. |
| `cooldownMs` | `number` | `5000` | Per-name gap before this event may fire again. |

### Policies

| Policy | Behaviour |
| --- | --- |
| idle_only | The default. Take a turn only if the avatar is not already busy. An avatar that talks over the user because they changed screens is worse than one that stays quiet. |
| queue | Wait for the current turn to finish, then take one. |
| interrupt | Cut in immediately. Reserve it for things the user genuinely needs to hear now. |
| context_only | Do not speak. Just remember it for later turns. |

### Limits

The SDK gates events before they reach the socket, so a chatty app cannot flood
the session.

| Limit | Value |
| --- | --- |
| Per-name cooldown | 5000ms (override with cooldownMs) |
| Rate limit | 5 events per 10s window |
| data length | 512 characters |
| say length | 1000 characters |

> A **dropped** event (cooldown or rate limit) is logged, never thrown — the gate
>   doing its job is not your bug. An **invalid** event (bad slug, oversized `data`
>   or `say`) is your bug, and surfaces as an `INVALID_INPUT` error.

> `readPage()` is **web only**. A React Native app has no page surface, so the
>   method is present on the hook for parity but always returns `null`. Use
>   `notify()` to tell the avatar where the user is instead.
