---
type: reference
title: Методы и события виджета
summary: Каждый метод, который ты можешь вызвать на элементах виджета Caputchin, и каждое событие, которое они испускают, с точной нагрузкой каждого, какой элемент его выставляет и когда он валиден.
---

Виджет Caputchin поставляет два пользовательских элемента, и твоя страница взаимодействует с ними в двух направлениях: ты **вызываешь методы** на элементе, чтобы им управлять, и ты **слушаешь события**, которые он испускает, чтобы реагировать. Эта страница это исчерпывающий справочник обеих поверхностей.

Каждое событие это `CustomEvent`, диспетчеризуемое с `bubbles: true` и `composed: true`, так что оно выходит из shadow DOM виджета, и ты можешь слушать его прямо на элементе (или на любом предке). Данные всегда на `event.detail`.

## Два элемента с первого взгляда

| Элемент | Назначение | Методы |
|---|---|---|
| `<caputchin-widget>` | Только проверка (proof-of-work / галочка). | `start()` |
| `<caputchin-game>` | Игровой хост, с опциональной проверкой. | `pass()`, `fail()` |

У галочного виджета только `start()`; он **не** выставляет `pass()` / `fail()`. У игрового хоста нет `start()` (его раунд становится живым при монтировании для inline или при первом открытии диалога для modal / fullscreen). Оба элемента испускают `start`, `pass`, `error` и `degraded`; игровой хост дополнительно испускает `dialog-shown` и `dialog-hidden`. Покрытие в [таблице событий](#events) ниже.

## Методы

### `start()` (только `<caputchin-widget>`)

Начинает проверку немедленно. Его назначение это **ручной триггер**: когда у элемента `trigger="manual"`, ты вызываешь `start()`, чтобы запустить решение proof-of-work от своего собственного жеста (например, при отправке твоей формы) вместо встроенной галочки. С триггерами по умолчанию `auto` / `click` элемент подключает свою собственную активацию, так что ты это не вызываешь.

```js
const widget = document.querySelector("caputchin-widget");
widget.start();
```

У игрового хоста нет `start()`. Смотри [ручной режим](/docs/custom-game-development/manual-mode) для полного прохождения управления-этим-самому.

### `pass(payload)` (только `<caputchin-game>`)

Отпускает ворота проверки: посетитель успел. **Валиден только когда `trigger="manual"`**; вызов его на не-ручной игре испускает `error` с кодом `invalid-call`. Первый `pass()` погашает и **блокирует** вердикт; поздние вызовы молча игнорируются (один раунд на сессию).

```js
const widget = document.querySelector("caputchin-game");
widget.pass({ trace: roundRecord });
```

| Поле `payload` | Тип | Значение |
|---|---|---|
| `trace` | `string` | Непрозрачная запись раунда, которую производит твоя игра. На раунде с воротами сервер реплеит её, чтобы вывести авторитетный вердикт; на ключе без ворот или только-игровом она принимается как есть. Передавай пустую строку, если у твоего взаимодействия нет записи для реплея. |

На этом методе нет поля `score`, ворота это реплей `trace` сервером, а не заявленный клиентом счёт. (`score` действительно появляется на [событии `pass`](#the-pass-event-and-the-token), которое это виджет, отчитывающийся обратно тебе, а не ты виджету.)

Вызов `pass()` до того, как раунд начался (modal / fullscreen, диалог ещё не открыт), испускает `error` с кодом `invalid-call`. На только-игровом ключе (нет `sitekey`) нет ворот для отпускания, так что `pass()` просто испускает событие `pass` с `token: null`.

### `fail(payload?)` (только `<caputchin-game>`)

Прерывает раунд: окончательный проигрыш. **Валиден только когда `trigger="manual"`** (иначе `invalid-call`). Опционален, незавершённый раунд всё равно трактуется как непрохождение. Он прерывает проверку в полёте (проверки proof-of-work и инструментирования) и всплывает событием `error` с кодом `game-error-relayed`.

```js
widget.fail({ code: "out-of-moves", message: "no moves left" });
```

| Поле `payload` | Тип | Значение |
|---|---|---|
| `code` | `string` (опционально) | Твой диагностический код; всплывает как `originalCode` события `error`. По умолчанию `game-failed`. |
| `message` | `string` (опционально) | Читаемая человеком причина. |

## События [#events]

Слушай через `addEventListener(type, handler)`. Каждая нагрузка живёт на `event.detail`.

| Событие | Испускается | `event.detail` | Срабатывает когда |
|---|---|---|---|
| `start` | оба | `{ gameId: string \| null }` | Проверка начинается (авто при монтировании, при активации или через `start()`). `gameId` задан для игрового раунда, `null` для простого виджета. |
| `pass` | оба | `{ token: string \| null, score: number \| null, durationMs: number \| null }` | Проверка отпущена. `token` это обёрнутый токен для отправки на твой бэкенд; `null` на только-игровом ключе (нет `sitekey`). |
| `error` | оба | `{ code, message, severity, originalCode? }` | Что угодно от безобидного предупреждения конфигурации до жёсткого сбоя. Смотри [событие error](#the-error-event). |
| `degraded` | оба | `{ reason: "timeout" \| "network" \| "http" \| "malformed" }` | Виджет не смог вовремя разрешить настроенные тобой размер / скин / локаль, поэтому отрендерился со своими встроенными значениями по умолчанию. Это не ошибка. Смотри [событие degraded](#the-degraded-event). |
| `dialog-shown` | `<caputchin-game>` | `{ layout: "modal" \| "fullscreen" }` | Диалог оверлея игры открывается (программно или первый клик). |
| `dialog-hidden` | `<caputchin-game>` | `{ layout: "modal" \| "fullscreen" }` | Диалог оверлея игры закрывается (программно, Escape или клик по затемнению). |

### Событие `pass` и токен [#the-pass-event-and-the-token]

Событие `pass` это твой сигнал, что проверка удалась, но это **не** решение о доверии. Решение о доверии это твой бэкенд, подтверждающий `detail.token`. Всегда [проверяй токен на своём бэкенде](/docs/integration-guides/verify-on-your-backend); никогда не давай доступ по одному фронтенд-событию. В форме виджет также вставляет токен как поле `caputchin-token`, чтобы обычный POST формы его нёс. `score` и `durationMs` на этом событии это аналитика, сообщённая клиентом, и могут быть `null`; никогда не трактуй их как сигнал доверия.

### Событие `error` [#the-error-event]

Событие `error` несёт стабильный `code`, человеческий `message`, `severity` и иногда `originalCode`. У каждого кода фиксированная серьёзность по умолчанию, так что ты можешь отфильтровать предупреждения «продолжило работать» от сбоев «реально сломалось» **без** жёсткой таблицы код-в-серьёзность, просто читай `detail.severity`. Полный набор кодов:

| `code` | `severity` | Значение |
|---|---|---|
| `invalid-config` | `warn` | Атрибут или сочетание, которое виджет отклонил; он деградирует мягко и продолжает работать. |
| `invalid-call` | `warn` | Метод, вызванный, когда он был невалиден (например `pass()` на не-ручной игре или до старта раунда). |
| `verification-failed` | `error` | Проверка proof-of-work или инструментирования (или погашение токена) сбоила; токен не выдан. |
| `game-load-failed` | `error` | Бандл игры не удалось разрешить, загрузить или зарегистрировать. |
| `gate-unavailable` | `error` | Сервер вернул авторитетный отказ при бутстрапе (ключ с воротами не смог поставить валидную игру). |
| `game-error-relayed` | `error` | Ошибка всплыла изнутри игры (ретранслирована из iframe или из ручного `fail()`). |

`detail.originalCode` присутствует, когда публичный `code` это обобщение более конкретной внутренней причины (например, сбой загрузки iframe, ретранслированный как `game-load-failed`, несёт сырой `iframe-load-failed` / `iframe-script-blocked` / `game-not-registered` в `originalCode`). Используй `code` для ветвления, а `originalCode` только для диагностики.

### Событие `degraded` [#the-degraded-event]

При монтировании виджет делает один короткий вызов к Caputchin, чтобы разрешить настроенные тобой размер, скин и локаль (а для игры из маркетплейса, её предпочтительный след). Если этот вызов сбоит или слишком медленный, виджет не блокируется и не ломается: он рендерится со значениями, запечёнными в бандл, и испускает `degraded`, так что откат к умолчанию никогда не бывает молчаливым. Виджет остаётся полностью рабочим после события `degraded`, лишь разрешённое представление может отличаться от того, что ты настроил (игра может появиться в своём размере по умолчанию, или галочка в своей теме по умолчанию). Виджет повторяет медленное разрешение перед откатом, так что `degraded` значит, что попытки исчерпаны, а не что одна попытка была медленной.

`detail.reason` говорит тебе, почему разрешение откатилось, чтобы ты мог показать это в своей собственной телеметрии:

| `reason` | Значение |
|---|---|
| `timeout` | Разрешение не ответило в рамках своего бюджета времени (сервис медленный или недостижим). |
| `network` | Сам запрос провалился (офлайн, DNS, заблокирован, или сброс соединения). |
| `http` | Сервис ответил статусом ошибки. |
| `malformed` | Сервис ответил, но тело было невалидным. |

`degraded` это уведомление, а не сбой, поэтому это намеренно **не** событие `error`: медленное разрешение не должно срабатывать обработчики, которые ты подключаешь для настоящих отказов. Слушай его только если хочешь наблюдать деградировавшие рендеры, например чтобы оповещать, когда твои посетители видят запасное представление.

## Слушание на практике

```js
const widget = document.querySelector("caputchin-game");

const onPass = (e) => {
  // send e.detail.token to your backend to verify
};
const onError = (e) => {
  if (e.detail.severity === "error") {
    console.error(e.detail.code, e.detail.message);
  }
};

widget.addEventListener("pass", onPass);
widget.addEventListener("error", onError);

// Clean up when you tear down your view:
widget.removeEventListener("pass", onPass);
widget.removeEventListener("error", onError);
```

Это нативные DOM-`CustomEvent`, так что в React ты подключаешь их через `ref` и `addEventListener` (а не JSX-пропсы `onPass`); [примеры фронтенда](/docs/integration-guides/frontend-examples) показывают фреймворк-специфичное подключение. Поскольку каждое событие всплывает и composed, ты можешь также делегировать с контейнерного элемента, а не привязывать каждый виджет по отдельности.

## См. также

- [Добавь виджет](/docs/getting-started/add-the-widget): атрибуты конфигурации, которые ты задаёшь в разметке (входная сторона к этой выходной).
- [Управляй проверкой сам через ручной режим](/docs/custom-game-development/manual-mode): руководство, которое использует `start()` / `pass()` / `fail()`.
- [Проверь на своём бэкенде](/docs/integration-guides/verify-on-your-backend): что делать с токеном события `pass`.
- [Примеры фронтенда](/docs/integration-guides/frontend-examples): подключение этих событий в React, Vue и чистом JS.
