> ## 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.

# Alerts

> Set up real-time alerts for high-value users, high-value transactions, and key user events, delivered via webhook or Slack.

<Frame caption="Alerts">
  <img src="https://mintcdn.com/formo/VYpB8FpAVxzzLcjy/images/alerts.png?fit=max&auto=format&n=VYpB8FpAVxzzLcjy&q=85&s=584c72ef228541cf4d06110d43d4220c" alt="Alerts" width="1338" height="914" data-path="images/alerts.png" />
</Frame>

Get notified in real time when high-value whales and important user actions happen:

* Key user events (connect wallet, transactions, conversions, drop off)
* When whales and high-value users visit your app

In the project settings page, you can create an alert that will notify you via:

* Webhooks (including Slack via incoming webhooks)

***

## How to set up your first alert

Get real-time notifications when high-value users interact with your app. This guide walks you through creating alerts for whale detection and key events.

### Step 1: Navigate to Alerts

1. Go to the [Formo Dashboard](https://app.formo.so)
2. Select your project
3. Click **Settings** in the left navigation (gear icon)
4. Select the **Alerts** tab

### Step 2: Create a new alert

1. Click **Create Alert**
2. Configure your alert:

| Setting | Description |
| - | - |
| **Name** | Descriptive name (e.g., "Whale Alert") |
| **Trigger Type** | Event or User (see below) |
| **Conditions** | Filter conditions (optional) |
| **Notification** | Webhook (generic HTTP or Slack via an incoming-webhook URL) |

### Step 3: Choose a trigger type

Formo supports two trigger types: **Event alerts**, which fire on individual matching events, and **User alerts**, which fire when a user profile matches your filters.

<Tabs>
  <Tab title="Events">
    Triggers when a new event matches your filters. Formo checks for matching events every 5 minutes; each matching event since the last check is sent to your webhook.

    | Event Type | When it fires |
    | - | - |
    | **connect** | User connects their wallet |
    | **transaction** | User submits a transaction |
    | **page** | User visits a specific page |
    | **custom** | Your custom tracked events |

    You can add conditions to filter on the event's top-level fields: `type`, `event`, `address`, `user_id`, `anonymous_id`, `location`, `device`, `browser`, `os`, and `referrer`. Conditions support exact match, contains, starts with, ends with, and not-equals (e.g., `browser = Chrome`, `referrer contains twitter`). They can't filter on values nested in `properties` (like `chain_id` or a transaction's `status`) or use numeric comparisons (`>`, `<`); use a User alert if you need to filter on a number.
  </Tab>

  <Tab title="Users">
    Triggers when a user profile matches your filters. Formo checks for matching users every 5 minutes and sends a notification for each new user that meets your filters.

    Each matching user is **notified once per 24 hours**: if the same user remains active and continues to match, they won't be re-sent until the dedup window expires.

    Available user filters:

    | Filter | Description |
    | - | - |
    | **net\_worth\_usd** | Wallet net worth (e.g., > \$100,000) |
    | **volume** | Trading volume |
    | **revenue** | Revenue generated |
    | **points** | Loyalty points |
    | **location** | Country code |
    | **device** | Device type (desktop, mobile) |
    | **browser** | Browser name |
    | **os** | Operating system |
    | **referrer / UTM** | Acquisition source filters |
    | **apps** | Specific onchain app usage |
    | **tokens** | Token holdings |
    | **chains** | Chain activity |
    | **labels** | Wallet labels (e.g., Coinbase verified) |
    | **lifecycle** | User lifecycle stage (New, Returning, etc.) |
    | **socials** | Social profiles (e.g., Farcaster) |

    `net_worth_usd`, `volume`, `revenue`, `points`, **apps**, **tokens**, and **chains** support numeric comparisons (`>`, `>=`, `<`, `<=`, `=`) against a usage threshold (e.g. chain activity > 10 transactions); the rest match on equality.
  </Tab>
</Tabs>

### Step 4: Configure notifications

<Tabs>
  <Tab title="Webhook">
    1. Select **Webhook** as the notification type
    2. Enter your webhook URL (generic HTTPS endpoint or Slack incoming webhook)
    3. Formo sends a POST request with batched data

    **Webhook security and signatures:**

    * Optional **secret**: In the alert configuration, you can provide a signing secret used to verify requests on your server.
    * For **generic webhooks** (non-Slack URLs), Formo uses your secret to compute an HMAC-SHA256 signature over the string `{timestamp}.{body}`, where:
      * `timestamp` is the Unix timestamp (seconds) used for the request
      * `body` is the exact JSON payload string sent in the request

    **HTTP headers sent:**

    | Header | Description |
    | - | - |
    | `Content-Type` | `application/json` |
    | `User-Agent` | `Formo-Alerts/1.0` |
    | `X-Formo-Alert-Id` | The alert ID in Formo |
    | `X-Webhook-Signature` | HMAC-SHA256 signature (generic webhooks with a secret only) |
    | `X-Webhook-Timestamp` | Unix timestamp used in the signature (generic webhooks with a secret only) |
    | `X-Webhook-Event` | `alert.event.triggered` or `alert.user.triggered` (generic webhooks with a secret only) |
  </Tab>

  <Tab title="Slack (via Webhook)">
    1. Create a [Slack incoming webhook](https://api.slack.com/messaging/webhooks)
    2. Use the Slack webhook URL as your Formo webhook URL
    3. Formo auto-detects `hooks.slack.com` URLs and formats messages as Slack Block Kit
    4. Messages post to your configured Slack channel with a formatted alert summary
  </Tab>
</Tabs>

### Step 5: Test your alert

1. Save your alert configuration
2. Trigger a test event:
   * Visit your app in a browser
   * Connect a wallet
   * Perform the action that matches your alert
3. Check your Slack channel or webhook endpoint for the notification

***

## Alert payloads

### Event alerts

When an event alert is triggered, Formo batches all matching events into a single webhook call.

#### Webhook payload

The webhook payload uses the `alert.event.triggered` event type and contains raw analytics events:

**Top-level properties:**

| Property | Type | Description |
| - | - | - |
| `id` | string | Unique event ID (e.g., `evt_3f7f9c4e-...`) |
| `type` | string | Always `alert.event.triggered` |
| `created` | number | Unix timestamp (seconds) when the webhook was created |
| `data` | array | Array of raw analytics events that matched your filters |

**Each event in `data`:**

| Property | Type | Description |
| - | - | - |
| `project_id` | string | Your Formo project ID |
| `session_id` | string | User session ID |
| `channel` | string | Event channel (e.g., `web`, `import`) |
| `type` | string | Event type (e.g., `connect`, `transaction`, `page`, `track`) |
| `anonymous_id` | string | Anonymous user ID |
| `user_id` | string | Identified user ID (if available) |
| `address` | string | Wallet address (if available) |
| `event` | string | Event name |
| `context` | object | Context data (IP, user agent) |
| `properties` | object | Event-specific properties |
| `version` | string | SDK version |
| `timestamp` | string | ISO 8601 timestamp |
| `message_id` | string | Unique message ID |
| `origin` | string | Origin domain |
| `locale` | string | User locale |
| `location` | string | Country code |
| `timezone` | string | User timezone |
| `page_path` | string | Page path |
| `page_title` | string | Page title |
| `page_url` | string | Full page URL |
| `page_query` | string | URL query string |
| `page_hash` | string | URL hash |
| `library_name` | string | SDK library name |
| `library_version` | string | SDK library version |
| `referrer_url` | string | Full referrer URL |
| `referrer` | string | Referrer domain |
| `ref` | string | Ref parameter |
| `utm_source` | string | UTM source |
| `utm_medium` | string | UTM medium |
| `utm_campaign` | string | UTM campaign |
| `utm_term` | string | UTM term |
| `utm_content` | string | UTM content |
| `user_agent` | string | Raw user agent string |
| `device` | string | Device type (e.g., `desktop`, `mobile`) |
| `browser` | string | Browser name |
| `os` | string | Operating system |

**Sample payload:**

```json theme={null}
{
  "id": "evt_3f7f9c4e-8b2c-4d1f-9a4b-4a2e9c1d2f01",
  "type": "alert.event.triggered",
  "created": 1739097600,
  "data": [
    {
      "project_id": "proj_123",
      "session_id": "sess_456",
      "channel": "web",
      "type": "connect",
      "anonymous_id": "4b48c7b6-3d61-409f-b695-1d9452954d6b",
      "user_id": "",
      "address": "0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc",
      "event": "Connected wallet",
      "context": {
        "ip": "203.0.113.10",
        "user_agent": "Mozilla/5.0 ..."
      },
      "properties": {
        "chain_id": 84532,
        "net_worth": 250000
      },
      "version": "1",
      "timestamp": "2026-02-09T06:42:16.519Z",
      "message_id": "msg_01J8ABCDEF1234567890",
      "origin": "app.formo.so",
      "locale": "en-US",
      "location": "VN",
      "timezone": "Asia/Saigon",
      "page_path": "/pricing",
      "page_title": "Pricing",
      "page_url": "https://app.formo.so/pricing",
      "page_query": "",
      "page_hash": "",
      "library_name": "@formo/sdk-js",
      "library_version": "1.0.0",
      "referrer_url": "https://google.com/",
      "referrer": "google.com",
      "ref": "",
      "utm_source": "google",
      "utm_medium": "cpc",
      "utm_campaign": "whale-acquisition",
      "utm_term": "",
      "utm_content": "",
      "user_agent": "Mozilla/5.0 (...)",
      "device": "desktop",
      "browser": "Chrome",
      "os": "MacOS"
    }
  ]
}
```

#### Slack payload

For Slack incoming webhooks (`hooks.slack.com`), Formo formats each event as an individual Slack Block Kit card message.

Each message includes:

* A **header** with the alert name
* A **user** link (clickable link to Formo profile, if available)
* **Event properties** (key-value pairs from the event)
* **Metadata fields**: Country, Device, Browser, OS, Referrer, Referral, UTM Source, UTM Medium, UTM Campaign, UTM Term, UTM Content - only shown when non-empty

**Sample Slack Block Kit payload (one event = one message):**

```json theme={null}
{
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": ":bell: Whale Alert",
        "emoji": true
      }
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "<https://app.formo.so/teams/team_1/projects/proj_123/users/0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc|0xF04bC8...E26bdc>"
      }
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*chain_id:* 84532\n*net_worth:* 250000"
      }
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*Country:* Vietnam\n*Device:* Desktop\n*Browser:* Chrome\n*OS:* MacOS\n*Referrer:* google.com\n*UTM Source:* google\n*UTM Medium:* cpc\n*UTM Campaign:* whale-acquisition"
      }
    }
  ]
}
```

***

### User alerts

When a user alert is triggered, Formo sends matching user profiles to your webhook.

#### Webhook payload

The webhook payload uses the `alert.user.triggered` event type:

**Top-level properties:**

| Property | Type | Description |
| - | - | - |
| `id` | string | Unique event ID (e.g., `evt_3f7f9c4e-...`) |
| `type` | string | Always `alert.user.triggered` |
| `created` | number | Unix timestamp (seconds) when the webhook was created |
| `data` | array | Array of user profiles that matched your filters |

**Each user in `data`** contains the full wallet profile. All fields from the profile are included; key properties:

**Wallet identity:**

| Property | Type | Description |
| - | - | - |
| `address` | string | Wallet address |
| `net_worth_usd` | number | Wallet net worth in USD |
| `tx_count` | number | Total transaction count |
| `first_onchain` | string | First on-chain transaction timestamp |
| `last_onchain` | string | Last on-chain transaction timestamp |
| `updated_at` | string | When the wallet profile was last updated |
| `ens` | string | ENS name |
| `farcaster` | string | Farcaster username |
| `lens` | string | Lens handle |
| `basenames` | string | Base name |
| `linea` | string | Linea name |
| `avatar` | string \| null | ENS/Farcaster avatar URL |
| `display_name` | string | Display name |
| `description` | string | Profile description |
| `profile_url` | string | Link to user profile in Formo dashboard |

**Socials** (included when available):

`discord`, `telegram`, `website`, `github`, `twitter`, `linkedin`, `email`, `instagram`, `facebook`, `tiktok`, `youtube`, `reddit`, `linea`

**Project-level engagement:**

| Property | Type | Description |
| - | - | - |
| `first_seen` | string | When the user was first seen (UTC) |
| `last_seen` | string | When the user was last active (UTC) |
| `num_sessions` | number | Total unique sessions |
| `revenue` | number | Total revenue |
| `volume` | number | Total transaction volume |
| `points` | number | Total loyalty points |
| `lifecycle` | string | Lifecycle stage (`New`, `Returning`, `Power user`, `At Risk`, `Churned`, `Resurrected`) |
| `activity_dates` | string\[] | Array of dates the user was active |
| `location` | string | Country code |
| `device` | string | Device type |
| `browser` | string | Browser name |
| `os` | string | Operating system |

**Attribution (first-touch and last-touch):**

| Property | Type | Description |
| - | - | - |
| `first_referrer` | string | First-touch referrer domain |
| `first_referrer_url` | string | First-touch full referrer URL |
| `first_ref` | string | First-touch referral code |
| `first_utm_source` | string | First-touch UTM source |
| `first_utm_medium` | string | First-touch UTM medium |
| `first_utm_campaign` | string | First-touch UTM campaign |
| `first_utm_term` | string | First-touch UTM term |
| `first_utm_content` | string | First-touch UTM content |
| `last_referrer` | string | Last-touch referrer domain |
| `last_referrer_url` | string | Last-touch full referrer URL |
| `last_ref` | string | Last-touch referral code |
| `last_utm_source` | string | Last-touch UTM source |
| `last_utm_medium` | string | Last-touch UTM medium |
| `last_utm_campaign` | string | Last-touch UTM campaign |
| `last_utm_term` | string | Last-touch UTM term |
| `last_utm_content` | string | Last-touch UTM content |

**Last activity:**

| Property | Type | Description |
| - | - | - |
| `last_type` | string | Last event type (e.g., `connect`, `page`, `track`) |
| `last_event` | string | Last event name |
| `last_properties` | string | JSON-encoded properties of the last event |

**Sample payload:**

```json theme={null}
{
  "id": "evt_a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "type": "alert.user.triggered",
  "created": 1739097600,
  "data": [
    {
      "address": "0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc",
      "net_worth_usd": 250000,
      "ens": "whale.eth",
      "farcaster": "",
      "lens": "",
      "basenames": "",
      "linea": "",
      "discord": "",
      "telegram": "",
      "website": "",
      "github": "",
      "twitter": "whale_trader",
      "linkedin": "",
      "email": "",
      "instagram": "",
      "facebook": "",
      "tiktok": "",
      "youtube": "",
      "reddit": "",
      "avatar": "https://euc.li/whale.eth",
      "display_name": "Whale",
      "description": "",
      "updated_at": "2026-02-09 06:40:00",
      "tx_count": 142,
      "first_onchain": "2022-03-15 12:00:00",
      "last_onchain": "2026-02-09 06:40:00",
      "profile_url": "https://app.formo.so/teams/team_1/projects/proj_123/users/0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc",
      "first_seen": "2025-11-15 08:30:00",
      "last_seen": "2026-02-09 06:42:16",
      "num_sessions": 47,
      "revenue": 5200.50,
      "volume": 89000.00,
      "points": 1500,
      "lifecycle": "Returning",
      "activity_dates": ["2026-02-09", "2026-02-08", "2026-02-05"],
      "location": "VN",
      "device": "desktop",
      "browser": "Chrome",
      "os": "MacOS",
      "first_referrer": "google.com",
      "first_referrer_url": "https://google.com/search?q=formo",
      "first_ref": "",
      "first_utm_source": "google",
      "first_utm_medium": "cpc",
      "first_utm_campaign": "whale-acquisition",
      "first_utm_term": "",
      "first_utm_content": "",
      "last_referrer": "twitter.com",
      "last_referrer_url": "https://twitter.com/formo",
      "last_ref": "",
      "last_utm_source": "twitter",
      "last_utm_medium": "social",
      "last_utm_campaign": "",
      "last_utm_term": "",
      "last_utm_content": "",
      "last_type": "connect",
      "last_event": "Connected wallet",
      "last_properties": "{\"chain_id\":8453}"
    }
  ]
}
```

#### Slack payload

For Slack incoming webhooks, Formo formats user profiles as a rich card layout:

* A **header** with the alert name
* Per user: a clickable address header with avatar image (if available), a **field grid** with key profile data, and a **View Profile** button
* Up to **25 users** per batch, with an overflow summary if more were found

**Default fields displayed:**

| Field | Source | Conditional |
| - | - | - |
| Lifecycle | `lifecycle` (e.g., New, Returning, Power user) | Yes - only shown when non-empty |
| Net Worth | `net_worth_usd` (formatted as `$1,234`) | No - always shown |
| First Seen | `first_seen` (formatted date) | No - always shown |
| Location | `location` | Yes - only shown when non-empty |
| Browser | `browser` | Yes - only shown when non-empty |
| Device | `device` | Yes - only shown when non-empty |
| OS | `os` | Yes - only shown when non-empty |
| Referrer | `first_referrer` or `last_referrer` | Yes - only shown when non-empty |
| Referral | `first_ref` or `last_ref` | Yes - only shown when non-empty |
| UTM | `first_utm_*` or `last_utm_*` (comma-joined) | Yes - only shown when non-empty |

**Sample Slack Block Kit payload:**

```json theme={null}
{
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": ":bell: Whale Alert",
        "emoji": true
      }
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*<https://app.formo.so/teams/team_1/projects/proj_123/users/0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc|0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc>*"
      },
      "accessory": {
        "type": "image",
        "image_url": "https://euc.li/whale.eth",
        "alt_text": "0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc"
      }
    },
    {
      "type": "section",
      "fields": [
        { "type": "mrkdwn", "text": "*Lifecycle:* Returning" },
        { "type": "mrkdwn", "text": "*Net Worth:* $250,000" },
        { "type": "mrkdwn", "text": "*First Seen:* Nov 15, 2025" },
        { "type": "mrkdwn", "text": "*Location:* VN" },
        { "type": "mrkdwn", "text": "*Browser:* Chrome" },
        { "type": "mrkdwn", "text": "*Device:* desktop" },
        { "type": "mrkdwn", "text": "*OS:* MacOS" },
        { "type": "mrkdwn", "text": "*Referrer:* google.com" },
        { "type": "mrkdwn", "text": "*UTM:* google, cpc, whale-acquisition" }
      ]
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": { "type": "plain_text", "emoji": true, "text": "View Profile" },
          "style": "primary",
          "url": "https://app.formo.so/teams/team_1/projects/proj_123/users/0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc",
          "value": "0xF04bC8FdFC8b1c03Fa77885574Ae6Ea041E26bdc"
        }
      ]
    }
  ]
}
```

***

## Examples

### Whale detection alert

Notify when high-value users visit:

| Setting | Value |
| - | - |
| Name | Whale Alert |
| Trigger type | Users |
| Condition | net\_worth\_usd > 100000 |
| Notification | Slack webhook |

Every time a wallet with over \$100k net worth is active, you'll get a Slack message with their profile.

### Failed transaction alert

Track when users encounter issues:

| Setting | Value |
| - | - |
| Name | Failed TX Alert |
| Trigger type | Events |
| Condition | type = transaction |
| Notification | Webhook |

`status` lives in the event's `properties` object, not a filterable top-level field, so this condition sends every transaction event. Filter for `properties.status = "failed"` on your webhook receiver to isolate failures.

### Webhook integration examples

**Send to Slack:**

```bash theme={null}
# Your Slack webhook URL
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
```

**Send to Zapier:**

```bash theme={null}
# Your Zapier webhook URL
https://hooks.zapier.com/hooks/catch/123456/abcdef/
```

Then use Zapier to route alerts to any destination: Notion, Airtable, Discord, SMS, etc.

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.