---
type: tutorial
title: 수동 모드로 검증을 직접 몰아가기
summary: 수동 모드는 당신 자신의 코드가 검증 수명 주기를 몰아가게 합니다. 그것은 다른 일을 하는 두 요소(체크박스 위젯과 게임 호스트)에 존재합니다; 이 페이지는 둘 다 빌드하고 각각을 언제 쓸지 보여 줍니다.
---

이 튜토리얼이 끝나면 당신은 내장 UI 대신 당신 자신의 코드에서 Caputchin 검증 수명 주기를, 당신의 경우에 맞는 두 요소 중 하나에서 몰아간 상태입니다. **수동 모드**(`trigger="manual"`)는 두 다른 요소에 존재하고, 그것들은 진짜로 다른 일을 합니다:

| 요소 | 수동 모드가 주는 것 | 당신이 몰아가는 것 |
|---|---|---|
| `<caputchin-widget>` | 내장 체크박스가 숨겨짐; 당신은 **당신 자신의 트리거**(폼 제출, 커스텀 버튼)에서 proof-of-work 풀이를 발사. 게임 없음. | `start()`(그다음 풀이는 보통 스스로 해소됨) |
| `<caputchin-game>` | iframe 없음; 당신은 **당신 자신의 게임 마크업**을 위젯의 레이아웃 셸에 슬롯하고 게임플레이에서 결과를 정함. | `pass()` / `fail()`(`start()` 없음; 라운드는 마운트 시 라이브) |

당신이 답하는 질문으로 고르세요:

- *"평소의 보이지 않는/체크박스 검증을 원하지만, 내 자신의 제스처로 트리거되고 기본 체크박스 없이."* → 아래의 **체크박스 위젯**.
- *"iframe 게임이 아니라 내 자신의 DOM에 렌더링되는 내 자신의 대화형 챌린지를 원하고, 내가 통과/실패를 정한다."* → 아래의 **게임 호스트**.

게임 경로가 어디에 맞는지는 [당신 자신의 게임 돌리기](/docs/custom-game-development/overview)를 읽으세요. 페이지에 위젯이 이미 있어야 합니다; 없으면 먼저 [위젯 추가](/docs/getting-started/add-the-widget)를 하세요.

둘이 공유하는 한 한계: 수동 모드 라운드는 **[게임 게이트](/docs/site-keys/games)를 충족할 수 없습니다**. 체크박스 요소는 키를 전혀 게이트하지 않고(오직 `<caputchin-game>`만 할 수 있습니다), 수동 `<caputchin-game>` 라운드에는 재생 가능한 트레이스가 없으니, 게이트된 키가 그것을 거부합니다. 수동 모드는 게이트되지 않은 키(proof-of-work 검증)나 게임 전용 용도를 위한 것입니다.

## 경로 A: 체크박스 위젯, 당신 자신의 트리거

표준 검증을 원하지만 그것을 당신이 직접 발사하고 싶을 때, 예를 들어 방문자가 폼을 제출할 때만 풀이를 돌리거나, 내장 체크박스 대신 당신 자신의 버튼 뒤에서 돌리려 할 때 이것을 쓰세요.

### 1. 요소를 수동으로 표시하기

```html
<caputchin-widget id="cap" sitekey="cpt_pub_..." trigger="manual"></caputchin-widget>
<button id="go" type="button">Verify and continue</button>
```

`trigger="manual"`이면, 내장 체크박스 UI가 숨겨집니다; 요소는 당신이 풀이를 시작하기를 기다립니다.

### 2. 당신의 제스처에서 풀이 시작하기

수동 모드의 체크박스 요소는 단일 메서드 `start()`를 노출합니다:

- `start()`는 체크박스 클릭을 대신해 proof-of-work 풀이를 발동합니다. `trigger="manual"`에서 유효합니다.

체크박스 위젯에는 `pass()` / `fail()`이 없습니다; `start()`를 호출하면, 풀이가 스스로 해소되고 `pass` 이벤트를 냅니다. (해제/중단 핸들은 게임 호스트에 살며, 경로 B에서 다룹니다.)

```js
const widget = document.getElementById("cap");

document.getElementById("go").addEventListener("click", () => {
  widget.start(); // begin verification now
});

widget.addEventListener("pass", () => {
  // token issued; submit your form / continue
});
```

풀이가 해소되면, 요소가 검증을 완료하고 (폼에서) 여느 위젯처럼 `caputchin-token` 필드를 주입합니다. 당신의 백엔드는 평소와 정확히 똑같이 [그 토큰을 검증](/docs/integration-guides/verify-on-your-backend)합니다; 수동 모드는 서버 측에서 아무것도 바꾸지 않습니다.

## 경로 B: 게임 호스트, 당신 자신의 DOM

iframe 게임을 로드하는 대신 당신 자신의 마크업에 당신 자신의 대화형 챌린지를 렌더링하고 결과를 직접 정하고 싶을 때 이것을 쓰세요.

### 1. 요소를 수동으로 표시하고 마크업 슬롯하기

`<caputchin-game>`에 `trigger="manual"`을 두고 그 안에 당신 자신의 마크업을 두세요. 다른 모든 모드에서 위젯은 라이트 DOM 자식을 무시합니다; 수동 모드는 위젯이 그것들을 `<slot>`을 통해 자기 레이아웃 셸에 투영하는 한 모드입니다.

```html
<caputchin-game id="cap" sitekey="cpt_pub_..." trigger="manual">
  <!-- Your own markup. The widget renders it inside its shell. -->
  <div id="my-game">
    <p>Tap the banana three times.</p>
    <button id="banana" type="button">🍌</button>
  </div>
</caputchin-game>
```

sitekey가 있고 키가 게이트되지 않으면, 위젯은 백그라운드에서 그 proof-of-work 확인을 돌립니다; 당신의 상호작용이 보이는 부분입니다. sitekey가 없으면(또는 `no-verify`), 게임 전용입니다: 당신의 상호작용이 검증할 것 없이 돕니다.

### 2. 당신의 코드에서 결과 몰아가기

수동 모드의 게임 호스트는 `pass()`와 `fail()`을 노출합니다. **`start()`는 없습니다**: 라운드는 요소가 마운트되면 라이브입니다(팩토리가 마운트되는 것이 시작 신호입니다).

- `pass(payload?)`는 검증을 해제합니다: 방문자가 성공했습니다. 한 번 호출하세요; 나중 호출은 무시됩니다(판정이 잠깁니다).
- `fail(payload?)`는 라운드를 중단합니다. 선택입니다; 끝나지 않은 라운드는 어쨌든 비통과로 다뤄집니다.

페이로드:

- `pass({ trace })`: `trace`는 당신의 상호작용이 내는 불투명 라운드 기록입니다. 게이트된 라운드에서는 서버가 판정을 위해 그것을 리플레이합니다; 게이트되지 않은 키나 게임 전용 키에서는 그것이 그대로 받아들여지니, 리플레이할 것이 없을 때는 빈 문자열(또는 단순 표식)을 넘기세요. 여기 클라이언트가 공급하는 점수는 없습니다.
- `fail({ code?, message? })`: 선택적 진단 `code`와 `message`, 둘 다 클라이언트 메타데이터, 결코 신뢰 신호 아님.

```js
const widget = document.getElementById("cap");
let taps = 0;

document.getElementById("banana").addEventListener("click", () => {
  taps += 1;
  if (taps >= 3) {
    widget.pass({ trace: `banana:${taps}` }); // visitor won
  }
});

// Optional: give up explicitly.
// widget.fail({ code: "gave-up", message: "closed the prompt" });
```

체크박스 경로와 마찬가지로, `pass()`는 검증을 완료하고 토큰을 주입합니다; 당신의 백엔드는 같은 방식으로 그것을 검증합니다.

## 결과에 반응하기 (두 경로)

당신 자신의 UI를 갱신하려면 위젯의 이벤트를 수신 대기하세요:

```js
widget.addEventListener("pass", () => {
  // verification released
});
widget.addEventListener("error", (e) => {
  console.warn("verification error", e.detail);
});
```

신뢰 결정은 늘 이벤트가 아니라 당신의 백엔드가 토큰을 확인하는 것입니다; 이벤트는 UX를 위한 것입니다.

## 수동 모드가 할 수 없는 것

- **사이트 키 게이트.** [게임 요구](/docs/site-keys/games)가 켜진 키는 체크박스 요소로 전혀 충족될 수 없고, 재생 가능한 트레이스가 없으니 수동 `<caputchin-game>`을 거부합니다(설정 시 구성 오류를 일으킵니다). 수동 모드는 게이트되지 않은 키나 게임 전용 키를 위한 것입니다.
- **커스텀 게임의 라운드 리플레이.** 게이트하는 게임이 필요하면, 수동 모드가 아니라 [자체 호스팅 iframe 게임](/docs/custom-game-development/self-hosted-game)으로 그것을 렌더링하고 트레이스를 내세요.

## 함께 보기

- [위젯 메서드와 이벤트](/docs/references/widget-methods-and-events): `start()` / `pass()` / `fail()`과 그것들이 내는 모든 이벤트의 전체 레퍼런스.
- [자체 호스팅 iframe 게임](/docs/custom-game-development/self-hosted-game): 게이트할 수 있는 샌드박스되고 재생 가능한 게임.
- [당신 자신의 게임 돌리기](/docs/custom-game-development/overview): 비교된 두 전달 모드.
- [백엔드에서 검증하기](/docs/integration-guides/verify-on-your-backend): pass가 내는 토큰 확인하기.
