---
type: reference
title: Metode dan event widget
summary: Setiap metode yang bisa kamu panggil pada elemen widget Caputchin dan setiap event yang mereka pancarkan, dengan payload persis masing-masing, elemen mana yang memaparkannya, dan kapan ia sah.
---

Widget Caputchin mengirim dua elemen kustom, dan halamanmu berinteraksi dengannya dalam dua arah: kamu **memanggil metode** pada elemen untuk mengemudikannya, dan kamu **mendengarkan event** yang ia pancarkan untuk bereaksi. Halaman ini adalah referensi menyeluruh untuk kedua permukaan.

Setiap event adalah `CustomEvent` yang dikirim dengan `bubbles: true` dan `composed: true`, jadi ia lolos dari shadow DOM widget dan kamu bisa mendengarkannya langsung pada elemen (atau pada leluhur mana pun). Datanya selalu di `event.detail`.

## Dua elemen sekilas

| Elemen | Tujuan | Metode |
|---|---|---|
| `<caputchin-widget>` | Hanya verifikasi (proof-of-work / checkbox). | `start()` |
| `<caputchin-game>` | Host game, dengan verifikasi opsional. | `pass()`, `fail()` |

Widget checkbox hanya punya `start()`; ia **tak** memaparkan `pass()` / `fail()`. Host game tak punya `start()` (rondenya menjadi hidup saat mount untuk inline, atau pada pembukaan dialog pertama untuk modal / fullscreen). Kedua elemen memancarkan `start`, `pass`, `error`, dan `degraded`; host game tambahan memancarkan `dialog-shown` dan `dialog-hidden`. Cakupan ada di [tabel event](#events) di bawah.

## Metode

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

Memulai verifikasi seketika. Tujuannya adalah **pemicu manual**: saat elemen punya `trigger="manual"`, kamu memanggil `start()` untuk menembakkan pemecahan proof-of-work dari gesturmu sendiri (misalnya, saat submit formulirmu) alih-alih checkbox bawaan. Dengan pemicu `auto` / `click` baku elemen menyambung aktivasinya sendiri, jadi kamu tak memanggil ini.

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

Host game tak punya `start()`. Lihat [mode manual](/docs/custom-game-development/manual-mode) untuk panduan mengemudikan-sendiri lengkapnya.

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

Melepaskan gerbang verifikasi: pengunjung berhasil. **Sah hanya saat `trigger="manual"`**; memanggilnya pada game non-manual memancarkan `error` dengan kode `invalid-call`. `pass()` pertama menebus dan **mengunci** vonis; panggilan berikutnya diabaikan diam-diam (satu ronde per sesi).

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

| Bidang `payload` | Tipe | Makna |
|---|---|---|
| `trace` | `string` | Catatan ronde opaque yang dihasilkan game-mu. Pada ronde bergerbang server memutarnya-ulang untuk menurunkan vonis otoritatif; pada key tak-bergerbang atau hanya-game ia diterima apa adanya. Lewatkan string kosong jika interaksimu tak punya catatan untuk diputar-ulang. |

Tak ada bidang `score` pada metode ini, gerbang adalah putar-ulang `trace` server, bukan skor yang diklaim-klien. (Sebuah `score` memang muncul di [event `pass`](#the-pass-event-and-the-token), yang adalah widget melaporkan kembali ke kamu, bukan kamu ke widget.)

Memanggil `pass()` sebelum ronde dimulai (modal / fullscreen, dialog belum dibuka) memancarkan `error` dengan kode `invalid-call`. Pada key hanya-game (tanpa `sitekey`) tak ada gerbang untuk dilepaskan, jadi `pass()` sekadar memancarkan event `pass` dengan `token: null`.

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

Membatalkan ronde: kekalahan definitif. **Sah hanya saat `trigger="manual"`** (kalau tidak `invalid-call`). Opsional, ronde yang tak selesai diperlakukan sebagai non-lolos toh. Ia membatalkan verifikasi yang sedang berlangsung (pemeriksaan proof-of-work dan instrumentasi) dan memunculkan event `error` dengan kode `game-error-relayed`.

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

| Bidang `payload` | Tipe | Makna |
|---|---|---|
| `code` | `string` (opsional) | Kode diagnostikmu; dimunculkan sebagai `originalCode` event `error`. Default ke `game-failed`. |
| `message` | `string` (opsional) | Alasan yang bisa-dibaca-manusia. |

## Event [#events]

Dengarkan dengan `addEventListener(type, handler)`. Setiap payload hidup di `event.detail`.

| Event | Dipancarkan oleh | `event.detail` | Menyala saat |
|---|---|---|---|
| `start` | keduanya | `{ gameId: string \| null }` | Verifikasi dimulai (auto saat mount, saat aktivasi, atau lewat `start()`). `gameId` disetel untuk ronde game, `null` untuk widget biasa. |
| `pass` | keduanya | `{ token: string \| null, score: number \| null, durationMs: number \| null }` | Verifikasi dilepaskan. `token` adalah token terbungkus untuk dikirim ke backend-mu; `null` pada key hanya-game (tanpa `sitekey`). |
| `error` | keduanya | `{ code, message, severity, originalCode? }` | Apa pun dari peringatan config benign hingga kegagalan keras. Lihat [event error](#the-error-event). |
| `degraded` | keduanya | `{ reason: "timeout" \| "network" \| "http" \| "malformed" }` | Widget tak bisa menyelesaikan ukuran / skin / locale yang kamu konfigurasi tepat waktu, jadi ia merender dengan nilai default bawaannya. Bukan sebuah galat. Lihat [event degraded](#the-degraded-event). |
| `dialog-shown` | `<caputchin-game>` | `{ layout: "modal" \| "fullscreen" }` | Sebuah dialog game overlay terbuka (programatik atau klik pertama). |
| `dialog-hidden` | `<caputchin-game>` | `{ layout: "modal" \| "fullscreen" }` | Sebuah dialog game overlay tertutup (programatik, Escape, atau klik latar). |

### Event `pass` dan token [#the-pass-event-and-the-token]

Event `pass` adalah isyaratmu bahwa verifikasi berhasil, tapi ia **bukan** keputusan kepercayaan. Keputusan kepercayaan adalah backend-mu yang memastikan `detail.token`. Selalu [verifikasi token di backend-mu](/docs/integration-guides/verify-on-your-backend); jangan pernah memberi akses dari event front-end saja. Di sebuah formulir, widget juga menyuntikkan token sebagai field `caputchin-token` agar POST formulir biasa membawanya. `score` dan `durationMs` pada event ini adalah analitik yang dilaporkan-klien dan bisa `null`; jangan pernah memperlakukannya sebagai sinyal kepercayaan.

### Event `error` [#the-error-event]

Event `error` membawa `code` stabil, `message` manusia, sebuah `severity`, dan kadang `originalCode`. Tiap kode punya severity default tetap agar kamu bisa menyaring peringatan "tetap berjalan" dari kegagalan "benar-benar rusak" **tanpa** mengeraskan-kode tabel kode-ke-severity, sekadar baca `detail.severity`. Set kode penuhnya:

| `code` | `severity` | Makna |
|---|---|---|
| `invalid-config` | `warn` | Sebuah atribut atau kombinasi yang ditolak widget; ia merosot dengan anggun dan tetap berjalan. |
| `invalid-call` | `warn` | Sebuah metode dipanggil saat ia tak sah (mis. `pass()` pada game non-manual, atau sebelum ronde dimulai). |
| `verification-failed` | `error` | Pemeriksaan proof-of-work atau instrumentasi (atau penebusan token) gagal; tak ada token diterbitkan. |
| `game-load-failed` | `error` | Bundel game tak bisa diselesaikan, dimuat, atau didaftarkan. |
| `gate-unavailable` | `error` | Server mengembalikan penolakan otoritatif saat bootstrap (key bergerbang tak bisa menyuplai game yang sah). |
| `game-error-relayed` | `error` | Sebuah galat muncul dari dalam game (diteruskan dari iframe, atau dari `fail()` manual). |

`detail.originalCode` hadir saat `code` publik adalah generalisasi dari alasan internal yang lebih spesifik (misalnya, kegagalan muatan iframe yang diteruskan sebagai `game-load-failed` membawa `iframe-load-failed` / `iframe-script-blocked` / `game-not-registered` mentah di `originalCode`). Pakai `code` untuk percabangan dan `originalCode` hanya untuk diagnostik.

### Event `degraded` [#the-degraded-event]

Saat mount, widget membuat satu panggilan pendek ke Caputchin untuk menyelesaikan ukuran, skin, dan locale yang kamu konfigurasi (dan, untuk game marketplace, jejak pilihannya). Jika panggilan itu gagal atau terlalu lambat, widget tak memblokir atau patah: ia merender dengan nilai yang dipanggang ke dalam bundel dan memancarkan `degraded` agar fallback tak pernah senyap. Widget tetap sepenuhnya berfungsi setelah event `degraded`, hanya presentasi terselesaikan yang mungkin berbeda dari yang kamu konfigurasi (sebuah game mungkin muncul pada ukuran defaultnya, atau checkbox dalam tema defaultnya). Widget mencoba ulang resolusi yang lambat sebelum jatuh ke fallback, jadi `degraded` berarti percobaan habis, bukan satu percobaan yang lambat.

`detail.reason` memberitahumu kenapa resolusi jatuh ke fallback, agar kamu bisa memunculkannya di telemetrimu sendiri:

| `reason` | Makna |
|---|---|
| `timeout` | Resolusi tak menjawab dalam anggaran waktunya (layanan lambat atau tak terjangkau). |
| `network` | Permintaan itu sendiri gagal (luring, DNS, terblokir, atau koneksi disetel-ulang). |
| `http` | Layanan menjawab dengan status galat. |
| `malformed` | Layanan menjawab, tapi badannya tak sah. |

`degraded` adalah pemberitahuan, bukan kegagalan, jadi ia sengaja **bukan** event `error`: resolusi lambat tak seharusnya memicu handler yang kamu kabelkan untuk kegagalan nyata. Dengarkan ia hanya jika kamu mau mengamati render terdegradasi, misalnya untuk memberi peringatan saat pengunjungmu melihat presentasi fallback.

## Mendengarkan, dalam praktik

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

Ini adalah `CustomEvent` DOM native, jadi di React kamu melekatkannya dengan `ref` dan `addEventListener` (bukan prop JSX `onPass`); [contoh frontend](/docs/integration-guides/frontend-examples) menunjukkan penyambungan spesifik-framework. Karena setiap event menggelembung dan ter-compose, kamu juga bisa mendelegasikan dari elemen kontainer ketimbang mengikat tiap widget satu per satu.

## Lihat juga

- [Tambahkan widget](/docs/getting-started/add-the-widget): atribut konfigurasi yang kamu setel di markup (sisi input untuk sisi output ini).
- [Kemudikan verifikasi sendiri dengan mode manual](/docs/custom-game-development/manual-mode): tutorial yang memakai `start()` / `pass()` / `fail()`.
- [Verifikasi di backend-mu](/docs/integration-guides/verify-on-your-backend): apa yang dilakukan dengan token event `pass`.
- [Contoh frontend](/docs/integration-guides/frontend-examples): menyambung event ini di React, Vue, dan JS murni.
