---
type: tutorial
title: 당신의 사이트에 위젯 추가하기
summary: React 문의 폼에 위젯을 추가하고, 대시보드에서 진짜 검증을 확인한 다음, Node 백엔드에서 그것을 강제하세요.
---

[이전 레슨](/docs/getting-started/create-your-account)에서 BananaSeed의 공개 키를 갖고 있습니다. 이제 React 문의 폼에 위젯을 올리고, 진짜 방문자가 그것을 푸는 모습을 대시보드에서 보고, 그런 다음 그것을 진짜 보호로 바꾸는 단 하나의 서버 호출을 더합니다.

## 끝나면 갖게 되는 것

- 문의 폼에 올라가 브라우저에서 방문자를 검증하는 위젯.
- 그 검증을 보여 주는 대시보드.
- 유효한 토큰 없는 모든 제출을 버리는 Node 백엔드.

## 1. React 폼에 위젯 추가하기

패키지를 설치하세요. 이것이 `<caputchin-widget>` 요소(그리고 다음 레슨을 위한 `<caputchin-game>` 요소)를 등록합니다:

```bash
npm install @caputchin/widget
```

앱 진입점(`main.jsx` 같은 곳)에서 시작할 때 한 번 임포트하세요:

```js
import "@caputchin/widget";
```

이제 BananaSeed의 문의 폼에 위젯을 올리세요. 체크박스가 풀리면 위젯은 폼에 숨겨진 `caputchin-token` 필드를 더하고, 당신은 그것을 제출 시 당신 자신의 필드처럼 읽습니다. `cpt_pub_...`을 당신의 공개 키로 바꾸세요:

```jsx
export function ContactForm() {
  async function handleSubmit(e) {
    e.preventDefault();
    const data = new FormData(e.currentTarget);
    await fetch("/api/contact", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        email: data.get("email"),
        message: data.get("message"),
        token: data.get("caputchin-token"),
      }),
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" required />
      <textarea name="message" required />
      <caputchin-widget sitekey="cpt_pub_..." />
      <button type="submit">Send</button>
    </form>
  );
}
```

빌드 단계 없는 순수 HTML 페이지거나 네이티브 모바일 앱인가요? [스크립트 태그 연동(CDN)](/docs/integration-guides/cdn)과 [모바일 앱 가이드](/docs/integration-guides/mobile-apps)를 보세요.

## 2. 검증되는 모습 보기

앱을 띄우고 문의 폼을 여세요. Caputchin 체크박스가 나타나 클릭 한 번 없이 스스로 닫힙니다. 폼을 제출할 필요조차 없습니다. 이것이 이미 진짜 검증이며, Caputchin에 닿았습니다.

## 3. 대시보드에서 확인하기

대시보드로 돌아가, 팀을 열고 사이트 키 안으로 들어가세요. 그 통계는 깔때기를 보여 줍니다: **세션 시작됨**, **브라우저에서 통과**, **서버에서 검증됨**, **위협 차단됨**. 페이지를 새로고침하세요. **세션 시작됨**과 **브라우저에서 통과**가 이제 둘 다 최소 `1`을 보여 줍니다. 그것이 당신의 방문입니다. 위젯이 로드되었고(시작됨) 챌린지가 브라우저에서 풀렸습니다(브라우저에서 통과), 백엔드는 전혀 없이.

**서버에서 검증됨**은 아직 `0`인데, 당신의 서버에서 아직 아무것도 토큰을 확인하지 않았기 때문입니다. 이 간극이 다음 단계입니다.

<Callout type="success">위젯이 라이브이고, 대시보드는 당신이 백엔드 코드 한 줄을 쓰기도 전에 이미 진짜 검증을 기록하고 있습니다. 🎉</Callout>

## 4. 백엔드에서 토큰 검증하기

브라우저에서 통과란 방문자가 챌린지를 풀었다는 뜻이지만, 당신의 서버가 토큰을 확인하기 전까지 폼은 보호되지 않습니다. 봇은 위젯을 완전히 무시하고 당신의 엔드포인트로 곧장 POST할 수 있습니다. 그래서 당신의 백엔드는 요청을 신뢰하기 전에 모든 토큰을 Caputchin으로 확인합니다. 당신의 시크릿(`cpt_sec_...`)은 환경 변수에 살지 절대 브라우저에 두지 않습니다:

```js
import express from "express";

const app = express();
app.use(express.json());

app.post("/api/contact", async (req, res) => {
  const { email, message, token } = req.body;

  const verdict = await fetch("https://verify.caputchin.com/v1/siteverify", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      secret: process.env.CAPUTCHIN_SECRET,
      response: token,
    }),
  }).then((r) => r.json());

  if (!verdict.success) {
    return res.status(400).json({ error: "Could not verify you are human." });
  }

  // Verified. Handle the real message: store it, email it, whatever you do.
  res.json({ ok: true });
});

app.listen(3001);
```

이 `verdict.success` 확인이 핵심입니다. `/api/contact`로 곧장 POST하는 봇은 토큰을 지니지 않으니 `success`가 `false`로 돌아오고, 메시지는 당신이 손대기도 전에 버려집니다.

백엔드가 없나요? 문제없습니다. [호스팅 인증](/docs/hosted-verification/overview)을 켜면 Caputchin이 이 확인을 대신 수행하고 검증된 제출만 웹훅이나 당신의 받은 편지함으로 전달합니다.

## 5. 서버 확인 검증하기

이제 엔드포인트가 검증하니, 문의 폼을 한 번 더 제출하세요. 사이트 키의 통계로 돌아가 새로고침하세요: **서버에서 검증됨**이 이제 시작됨과 브라우저에서 통과 옆에서 함께 최소 `1`을 보여 줍니다. 깔때기 전체가 브라우저에서 서버까지 덮였습니다.

이 깔때기를 거꾸로 읽으려면(카운터 사이의 간극이 방문자 이탈과 연동 오류에 대해 무엇을 말해 주는지) [통계와 세션](/docs/site-keys/statistics)을 보세요.

<Callout type="success">당신의 문의 폼은 이제 진짜로 보호됩니다: 모든 제출이 당신의 서버에서 확인되고, 토큰 없는 봇은 돌려보내집니다. 🎉</Callout>

## 방금 일어난 일

| 단계 | 어디서 | 결과 |
|---|---|---|
| 폼의 `<caputchin-widget>` | React | 체크박스가 마운트 시 검증하고 일회용 `caputchin-token` 필드를 더합니다. |
| 페이지 열기 | 브라우저 | 시작됨과 브라우저에서 통과가 올라갑니다, 백엔드 불필요. |
| 시크릿과 함께 `/siteverify` | Node에서 Caputchin으로 | `success: true`는 요청을 통과시키고, 토큰 없음은 폐기를 뜻하며, 서버에서 검증됨이 올라갑니다. |

## 자주 묻는 질문

### 위젯을 쓰는 데 백엔드가 필요한가요?

브라우저 단계에는 필요 없습니다. 진짜 보호에는 필요합니다. 위젯은 브라우저 안에서 스스로 검증하지만, 봇은 그것을 무시하고 당신의 엔드포인트로 곧장 POST할 수 있으니, 당신의 서버가 제출을 신뢰하기 전에 `caputchin-token`을 확인해야 합니다. 백엔드를 돌리지 않는다면 [호스팅 인증](/docs/hosted-verification/overview)을 켜면 Caputchin이 그 확인을 대신 수행합니다.

### 위젯이 로드된 뒤에도 왜 서버에서 검증됨이 여전히 0인가요?

당신의 서버에서 아직 아무것도 토큰을 확인하지 않았기 때문입니다. 시작됨과 브라우저에서 통과는 브라우저만으로 올라갑니다; 서버에서 검증됨은 당신의 백엔드가 `/siteverify`를 호출해야 비로소 올라가며, 그것이 [4단계](#4-백엔드에서-토큰-검증하기)입니다.

### 위젯이 React 밖에서도 동작하나요?

네. 표준 커스텀 요소라서 같은 하나의 태그로 순수 HTML, Vue, Svelte, Angular, 또는 네이티브 앱 WebView에 들어갑니다. [클라이언트 측 연동](/docs/integration-guides/cdn)과 [모바일 앱 가이드](/docs/integration-guides/mobile-apps)를 보세요.

### 내 시크릿 키는 어디로 가나요?

오직 당신의 서버에, 환경 변수(`cpt_sec_...`) 안에 둡니다. 그것은 `/siteverify` 호출을 인증하며, 절대 브라우저로 보내서는 안 됩니다.

## 다음

체크박스가 동작합니다. 이제 재미있는 부분입니다: 백엔드는 바꾸지 않고 그것을 진짜 플레이 가능한 게임으로 교체하세요.

[마켓플레이스에서 게임 추가하기](/docs/getting-started/add-a-game)로 계속하세요.
