> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formo.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Token gating

> Restrict form access by requiring responders to hold specific ERC-20 tokens, NFTs, or complete identity verification before submitting responses.

<Frame>
  <img src="https://mintcdn.com/formo/Qbe3dL6juMIXAS6y/images/token-gated-forms-token-gate-3.png?fit=max&auto=format&n=Qbe3dL6juMIXAS6y&q=85&s=384291e3808e06ef1c40f0c32a6376c5" alt="Token Gated Form Builder" width="1504" height="1124" data-path="images/token-gated-forms-token-gate-3.png" />
</Frame>

Formo supports token gating, giving you full control over who can access your forms.

## Quickstart

<Frame>
  <img src="https://mintcdn.com/formo/Qbe3dL6juMIXAS6y/images/token-gated-forms-token-gate-0.png?fit=max&auto=format&n=Qbe3dL6juMIXAS6y&q=85&s=1cb8cdcea510d898f96342e3ed3f9b3a" alt="Token Gated Form Builder" width="1850" height="1468" data-path="images/token-gated-forms-token-gate-0.png" />
</Frame>

<Steps>
  <Step title="Create a form">
    Sign in to [app.formo.so](https://app.formo.so) to create your form.
  </Step>

  <Step title="Enable token gating">
    Go to your form's *settings* page to enable token gating.
  </Step>

  <Step title="Add requirements">
    Click *Add Requirement* to add one or more gating requirements.
  </Step>

  <Step title="Publish">
    Publish your form and share the link with your users!
  </Step>
</Steps>

Your form will verify that responders fulfill your requirements before continuing. Formo currently supports [40+ chains](/chains/overview).

<Frame>
  <img src="https://mintcdn.com/formo/Qbe3dL6juMIXAS6y/images/token-gated-forms-token-gate-1.png?fit=max&auto=format&n=Qbe3dL6juMIXAS6y&q=85&s=ca0490cff75bb520155b5c8cad1bd5d5" alt="Token Gated Form Builder" width="1142" height="544" data-path="images/token-gated-forms-token-gate-1.png" />
</Frame>

Choose from different types of token gating requirements:

<Frame>
  <img src="https://mintcdn.com/formo/Qbe3dL6juMIXAS6y/images/token-gated-forms-token-gate-2.png?fit=max&auto=format&n=Qbe3dL6juMIXAS6y&q=85&s=2e59176296e40e9b8b099809cce8fd95" alt="Token Gated Form Builder" width="1000" height="994" data-path="images/token-gated-forms-token-gate-2.png" />
</Frame>

## Native Token

Require responders to hold a minimum balance of a chain's native token (e.g., ETH, MATIC, BNB).

### Setup

1. In your form settings, click **Add Requirement** and select **Native Token**
2. Choose the **chain** (Ethereum, Base, Polygon, etc.)
3. Set the **minimum balance** required

### Example

Require at least 0.1 ETH on Ethereum Mainnet:

| Field           | Value        |
| --------------- | ------------ |
| Type            | Native Token |
| Chain           | Ethereum     |
| Minimum balance | 0.1          |

## ERC-20 Token

Require responders to hold a minimum amount of a specific ERC-20 token.

### Setup

1. In your form settings, click **Add Requirement** and select **ERC-20**
2. Choose the **chain** where the token is deployed
3. Paste the **token contract address**
4. Set the **minimum balance** required

### Example

Require at least 1,000 USDC on Base:

| Field            | Value                                        |
| ---------------- | -------------------------------------------- |
| Type             | ERC-20                                       |
| Chain            | Base                                         |
| Contract address | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
| Minimum balance  | 1000                                         |

<Tip>
  Formo automatically detects the token name, symbol, and decimals from the contract address.
</Tip>

## NFT

Require responders to hold one or more NFTs from a specific collection (ERC-721 or ERC-1155).

### Setup

1. In your form settings, click **Add Requirement** and select **NFT**
2. Choose the **chain** where the NFT collection is deployed
3. Paste the **NFT contract address**
4. Set the **minimum quantity** (defaults to 1)

### Example

Require at least 1 NFT from a collection on Ethereum:

| Field            | Value                       |
| ---------------- | --------------------------- |
| Type             | NFT                         |
| Chain            | Ethereum                    |
| Contract address | Your NFT collection address |
| Minimum quantity | 1                           |

## Contract Read

Gate form access based on any smart contract's read function. This is useful for verifying staking balances, governance power, protocol participation, or any other onchain state that can be queried from a contract.

### How it works

Contract Read calls a read-only function on a smart contract and compares the result against a value you specify. The responder's wallet address can be passed as a function argument using the `{{address}}` placeholder.

**Example:** Require that the responder has staked at least 100 WCT tokens by reading the `stakedBalance(address)` function.

### Setup

<Steps>
  <Step title="Add a Contract Read requirement">
    In your form settings, click **Add Requirement** and select **Contract Read**.
  </Step>

  <Step title="Select the chain">
    Choose the chain where your contract is deployed (Ethereum, Base, Arbitrum, etc.)
  </Step>

  <Step title="Enter the contract address">
    Paste the smart contract address (e.g., `0x1234...abcd`).
  </Step>

  <Step title="Provide the ABI">
    Paste the contract ABI (JSON format). For verified contracts, you can copy the ABI from Etherscan.
  </Step>

  <Step title="Select a function">
    Choose a read-only function from the ABI. Only `view` and `pure` functions are available.
  </Step>

  <Step title="Configure function arguments">
    Enter the function arguments. Use `{{address}}` as a placeholder for the responder's wallet address.
  </Step>

  <Step title="Set the condition">
    Choose a comparison operator and the expected value:

    | Operator | Meaning               |
    | -------- | --------------------- |
    | `>`      | Greater than          |
    | `>=`     | Greater than or equal |
    | `<`      | Less than             |
    | `<=`     | Less than or equal    |
    | `==`     | Equal to              |
    | `!=`     | Not equal to          |
  </Step>

  <Step title="Publish">
    Publish your form. Formo will verify each responder's wallet against the contract before allowing submission.
  </Step>
</Steps>

### Example: Staking requirement

Gate access to users who have staked at least 100 tokens:

| Field            | Value                                                 |
| ---------------- | ----------------------------------------------------- |
| Chain            | Ethereum                                              |
| Contract address | Your staking contract                                 |
| Function         | `stakedBalance(address)`                              |
| Arguments        | `{{address}}`                                         |
| Operator         | `>=`                                                  |
| Value            | `100000000000000000000` (100 tokens with 18 decimals) |

<Tip>
  Values are compared as raw integers. For ERC-20 tokens with 18 decimals, 100 tokens = `100000000000000000000` (100 \* 10^18).
</Tip>

### Example: Governance power

Require a minimum voting power to access a governance feedback form:

| Field            | Value                                  |
| ---------------- | -------------------------------------- |
| Chain            | Base                                   |
| Contract address | Your governance token                  |
| Function         | `getVotes(address)`                    |
| Arguments        | `{{address}}`                          |
| Operator         | `>=`                                   |
| Value            | `1000000000000000000000` (1000 tokens) |

### Supported functions

Contract Read supports any `view` or `pure` function that:

* Returns a single scalar value (number, boolean, address, or string)
* Takes scalar input parameters (no arrays or structs)

Common use cases include `balanceOf`, `stakedBalance`, `getVotes`, `isWhitelisted`, `hasRole`, and any custom getter function on your contract.
