---
type: reference
title: Métodos y eventos del widget
summary: Cada método que puedes llamar en los elementos del widget de Caputchin y cada evento que emiten, con el payload exacto de cada uno, qué elemento lo expone, y cuándo es válido.
---

El widget de Caputchin incluye dos custom elements, y tu página interactúa con ellos en dos direcciones: **llamas métodos** en el elemento para conducirlo, y **escuchas eventos** que emite para reaccionar. Esta página es la referencia exhaustiva de ambas superficies.

Cada evento es un `CustomEvent` despachado con `bubbles: true` y `composed: true`, así que escapa del shadow DOM del widget y puedes escucharlo directamente en el elemento (o en cualquier ancestro). Los datos están siempre en `event.detail`.

## Los dos elementos de un vistazo

| Elemento | Propósito | Métodos |
|---|---|---|
| `<caputchin-widget>` | Solo verificación (proof-of-work / checkbox). | `start()` |
| `<caputchin-game>` | Anfitrión de juego, con verificación opcional. | `pass()`, `fail()` |

El widget de checkbox tiene solo `start()`; **no** expone `pass()` / `fail()`. El anfitrión de juego no tiene `start()` (su ronda se vuelve en vivo al montarse para inline, o al primer abrir del diálogo para modal / fullscreen). Ambos elementos emiten `start`, `pass`, `error`, y `degraded`; el anfitrión de juego además emite `dialog-shown` y `dialog-hidden`. La cobertura está en la [tabla de eventos](#events) de abajo.

## Métodos

### `start()` (solo `<caputchin-widget>`)

Empieza la verificación de inmediato. Su propósito es el **disparador manual**: cuando el elemento tiene `trigger="manual"`, llamas a `start()` para disparar la resolución de proof-of-work desde tu propio gesto (por ejemplo, al enviar tu formulario) en vez de la checkbox integrada. Con los disparadores `auto` / `click` por defecto el elemento cablea su propia activación, así que no llamas a esto.

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

El anfitrión de juego no tiene `start()`. Mira [modo manual](/docs/custom-game-development/manual-mode) para el recorrido completo de conducirlo-tú-mismo.

### `pass(payload)` (solo `<caputchin-game>`)

Libera el gate de verificación: el visitante tuvo éxito. **Válido solo cuando `trigger="manual"`**; llamarlo en un juego no-manual emite un `error` con el código `invalid-call`. El primer `pass()` canjea y **bloquea** el veredicto; las llamadas posteriores se ignoran en silencio (una ronda por sesión).

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

| Campo de `payload` | Tipo | Significado |
|---|---|---|
| `trace` | `string` | El registro opaco de ronda que tu juego produce. En una ronda con gate el servidor la repite para derivar el veredicto autoritativo; en una clave sin gate o solo-juego se acepta tal cual. Pasa una cadena vacía si tu interacción no tiene registro que repetir. |

No hay campo `score` en este método, el gate es la repetición del `trace` por el servidor, no una puntuación declarada por el cliente. (Un `score` sí aparece en el [evento `pass`](#the-pass-event-and-the-token), que es el widget reportándote de vuelta, no tú al widget.)

Llamar a `pass()` antes de que la ronda haya empezado (modal / fullscreen, diálogo aún no abierto) emite un `error` con el código `invalid-call`. En una clave solo-juego (sin `sitekey`) no hay gate que liberar, así que `pass()` simplemente emite el evento `pass` con `token: null`.

### `fail(payload?)` (solo `<caputchin-game>`)

Aborta la ronda: una derrota definitiva. **Válido solo cuando `trigger="manual"`** (de lo contrario `invalid-call`). Opcional, una ronda sin terminar se trata como un no-pass de todos modos. Aborta la verificación en curso (las comprobaciones de proof-of-work e instrumentación) y hace aflorar un evento `error` con el código `game-error-relayed`.

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

| Campo de `payload` | Tipo | Significado |
|---|---|---|
| `code` | `string` (opcional) | Tu código de diagnóstico; aflorado como el `originalCode` del evento `error`. Por defecto `game-failed`. |
| `message` | `string` (opcional) | Motivo legible por humanos. |

## Eventos [#events]

Escucha con `addEventListener(type, handler)`. Cada payload vive en `event.detail`.

| Evento | Emitido por | `event.detail` | Se dispara cuando |
|---|---|---|---|
| `start` | ambos | `{ gameId: string \| null }` | Empieza la verificación (auto al montarse, en la activación, o vía `start()`). `gameId` está fijado para una ronda de juego, `null` para el widget simple. |
| `pass` | ambos | `{ token: string \| null, score: number \| null, durationMs: number \| null }` | La verificación se libera. `token` es el token envuelto para enviar a tu backend; `null` en una clave solo-juego (sin `sitekey`). |
| `error` | ambos | `{ code, message, severity, originalCode? }` | Cualquier cosa desde un warning de config benigno hasta un fallo duro. Mira [el evento error](#the-error-event). |
| `degraded` | ambos | `{ reason: "timeout" \| "network" \| "http" \| "malformed" }` | El widget no pudo resolver a tiempo el tamaño / skin / locale que configuraste, así que renderizó con sus valores por defecto empaquetados. No es un error. Mira [el evento degraded](#the-degraded-event). |
| `dialog-shown` | `<caputchin-game>` | `{ layout: "modal" \| "fullscreen" }` | Un diálogo de juego en overlay se abre (programático o primer clic). |
| `dialog-hidden` | `<caputchin-game>` | `{ layout: "modal" \| "fullscreen" }` | Un diálogo de juego en overlay se cierra (programático, Escape, o clic en el fondo). |

### El evento `pass` y el token [#the-pass-event-and-the-token]

El evento `pass` es tu señal de que la verificación tuvo éxito, pero **no** es la decisión de confianza. La decisión de confianza es tu backend confirmando `detail.token`. [Verifica siempre el token en tu backend](/docs/integration-guides/verify-on-your-backend); nunca concedas acceso solo del evento del front-end. En un formulario, el widget también inyecta el token como un campo `caputchin-token` para que un POST normal de formulario lo lleve. El `score` y el `durationMs` de este evento son analítica reportada por el cliente y pueden ser `null`; nunca los trates como una señal de confianza.

### El evento `error` [#the-error-event]

El evento `error` lleva un `code` estable, un `message` humano, una `severity`, y a veces un `originalCode`. Cada código tiene una severity por defecto fija para que puedas filtrar los warnings de "siguió corriendo" de los fallos de "de verdad se rompió" **sin** codificar a mano una tabla de código-a-severity, solo lee `detail.severity`. El conjunto completo de códigos:

| `code` | `severity` | Significado |
|---|---|---|
| `invalid-config` | `warn` | Un atributo o combinación que el widget rechazó; degrada con gracia y sigue corriendo. |
| `invalid-call` | `warn` | Un método llamado cuando no era válido (p. ej. `pass()` en un juego no-manual, o antes de que la ronda empezara). |
| `verification-failed` | `error` | La comprobación de proof-of-work o instrumentación (o el canje del token) falló; no se emitió token. |
| `game-load-failed` | `error` | El bundle del juego no se pudo resolver, cargar, o registrar. |
| `gate-unavailable` | `error` | El servidor devolvió un rechazo autoritativo en el bootstrap (una clave con gate no pudo suministrar un juego válido). |
| `game-error-relayed` | `error` | Un error afloró desde dentro del juego (retransmitido desde el iframe, o de un `fail()` manual). |

`detail.originalCode` está presente cuando el `code` público es una generalización de un motivo interno más concreto (por ejemplo, un fallo de carga de iframe retransmitido como `game-load-failed` lleva el `iframe-load-failed` / `iframe-script-blocked` / `game-not-registered` crudo en `originalCode`). Usa `code` para ramificar y `originalCode` solo para diagnóstico.

### El evento `degraded` [#the-degraded-event]

Al montarse, el widget hace una llamada corta a Caputchin para resolver el tamaño, skin y locale que configuraste (y, para un juego del marketplace, su footprint preferido). Si esa llamada falla o es demasiado lenta, el widget no se bloquea ni se rompe: renderiza con los valores horneados en el bundle y emite `degraded` para que el fallback nunca sea silencioso. El widget sigue plenamente funcional tras un evento `degraded`, solo que la presentación resuelta puede diferir de lo que configuraste (un juego puede aparecer en su tamaño por defecto, o el checkbox en su tema por defecto). El widget reintenta una resolución lenta antes de caer al fallback, así que `degraded` significa que los reintentos se agotaron, no que un solo intento fuera lento.

`detail.reason` te dice por qué la resolución cayó al fallback, para que puedas mostrarlo en tu propia telemetría:

| `reason` | Significado |
|---|---|
| `timeout` | La resolución no respondió dentro de su presupuesto de tiempo (servicio lento o inalcanzable). |
| `network` | La solicitud misma falló (offline, DNS, bloqueada, o conexión reiniciada). |
| `http` | El servicio respondió con un estado de error. |
| `malformed` | El servicio respondió, pero el cuerpo no era válido. |

`degraded` es un aviso, no un fallo, así que deliberadamente **no** es un evento `error`: una resolución lenta no debería disparar los handlers que cableas para fallos reales. Escúchalo solo si quieres observar los renders degradados, por ejemplo para alertar cuando tus visitantes están viendo la presentación de fallback.

## Escuchar, en la práctica

```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);
```

Estos son `CustomEvent`s nativos del DOM, así que en React los adjuntas con un `ref` y `addEventListener` (no props JSX `onPass`); los [ejemplos de frontend](/docs/integration-guides/frontend-examples) muestran el cableado específico de cada framework. Como cada evento burbujea y es composed, también puedes delegar desde un elemento contenedor en vez de ligar cada widget individualmente.

## Véase también

- [Añade el widget](/docs/getting-started/add-the-widget): los atributos de configuración que fijas en el markup (el lado de entrada de este lado de salida).
- [Conduce la verificación tú mismo con el modo manual](/docs/custom-game-development/manual-mode): el tutorial que usa `start()` / `pass()` / `fail()`.
- [Verifica en tu backend](/docs/integration-guides/verify-on-your-backend): qué hacer con el token del evento `pass`.
- [Ejemplos de frontend](/docs/integration-guides/frontend-examples): cablear estos eventos en React, Vue, y JS plano.
