---
title: "Use bot defence in your app"
description: "Score the sign-in, sign-up, reset and invite doors in process, challenge or refuse bots with a proof-of-work, and stop SMS and WhatsApp pumping before a message is paid for."
section: "guides"
status: "Building for 0.3"
spec: "bot-defence"
canonical: "https://mainsdk.dev/docs/guides/use-bots"
updated: "2026-10-28"
---

# Use bot defence in your app

> Score the sign-in, sign-up, reset and invite doors in process, challenge or refuse bots with a proof-of-work, and stop SMS and WhatsApp pumping before a message is paid for.

Status: Building for 0.3 · Canonical: https://mainsdk.dev/docs/guides/use-bots · Updated: 2026-10-28

You will add `bots` to your app and check that it works. It takes about 15 minutes.

## You need

- A MainSDK app with a `main.yaml` (see [Thirty-minute path](https://mainsdk.dev/docs/getting-started/thirty-minutes)).

## 1. Turn it on

Add a `bots` section. The five built-in doors (`sign-in`, `sign-up`, `reset`, `whatsapp`, `invite`) are scored with sensible thresholds. Start in `observe` to see what would be challenged.

```yaml title="main.yaml"
bots:
  mode: observe
```

## 2. Protect a form of your own

Declare the door, render the token and honeypot in the page, and the engine refuses a post without a valid token with `MAIN-BOT-0004`.

```yaml title="main.yaml"
bots:
  doors:
    contact: { path: /api/contact, form: true }
```

```ts title="app/contact.ts"
import { bots } from "mainsdk/bots";

const { html } = bots.formFields();   // put this inside your <form>
```

## 3. Solve challenges in the browser

```ts title="web/send.ts"
import { fetchWithChallenge } from "mainsdk/bots/client";

export async function send(data: FormData) {
  return fetchWithChallenge("/api/contact", { method: "POST", body: data });
}
```

## 4. Stop message pumping

Set the countries you serve and the send limits. The WhatsApp code send refuses before any message is paid for.

```yaml title="main.yaml"
bots:
  pumping: { per-prefix: { max: 10, per: 1h }, countries: [IN] }
```

## Check it worked

Run `npx mainsdk check`. It passes when `bots` is configured as shown.
