# Click Tracking

## How It Works

When click tracking is enabled for a route, Lettermint automatically rewrites links in your HTML emails to route through our tracking domain. The original link:

```html
<a href="https://example.com/product/123">View Product</a>
```

Becomes:

```html
<a href="https://p{sid}.t.ltrmnt.com/c/{tracking_token}">View Product</a>
```

Where `{sid}` is your project's short ID.

:::tip
Want branded tracking links? [Custom tracking domains](/platform/emails/tracking/custom-domains) let you use your own subdomain (e.g., `track.yourcompany.com`) instead of the default tracking domain. Available on Pro plans.
:::

### Redirect Flow

When a recipient clicks a tracked link:

1. **Click observed** — Request hits the tracking domain and we store the click observation with timestamp
2. **Token validated** - We verify the tracking token is valid and not expired
3. **Instant redirect** - Recipient is immediately redirected (302) to the original URL
4. **Classification and promotion** - The observation is classified before it contributes to customer-visible events and metrics
5. **Webhook sent** - Human-countable clicks send a `message.clicked` event to your configured webhooks

The redirect happens in milliseconds, providing a seamless experience for recipients.

## Enabling Click Tracking

### Via Dashboard

1. Navigate to your project
2. Go to **Routes** and select your transactional or broadcast route
3. In **Route Settings**, enable **Track Clicks**
4. Save your changes

### Via API

```bash
curl -X PATCH https://api.lettermint.co/v1/routes/{route_id} \
  -H "Authorization: Bearer {team_api_token}" \
  -H "Content-Type: application/json" \
  -d '{"track_clicks": true}'
```

:::note
Click tracking is only available for **transactional** and **broadcast** routes. Inbound routes cannot have tracking enabled.
:::

### Per-Email Override

You can override the route's click tracking setting for a single email. This lets you keep a route default while opting individual messages in or out.

API sends use `settings.track_clicks`:

```json
{
  "from": "sender@yourdomain.com",
  "to": ["recipient@example.com"],
  "subject": "Your download link",
  "html": "<p><a href=\"https://example.com/download\">Download</a></p>",
  "settings": {
    "track_clicks": false
  }
}
```

SMTP sends use the Lettermint override header:

```text
X-LM-Override-Track-Clicks: false
```

The override applies only to that email and takes precedence over the selected route's **Track Clicks** setting.

## Which Links Are Tracked

### Tracked Links

Lettermint rewrites standard HTTP/HTTPS links:

- `https://example.com/page`
- `http://example.com/page`
- Links in `<a href="...">` tags
- Links in HTML email content

### Skipped Links

The following link types are **not** rewritten to preserve functionality:

| Link Type | Example | Reason |
|-----------|---------|--------|
| Email links | `mailto:support@example.com` | Opens email client |
| Phone links | `tel:+1234567890` | Opens phone dialer |
| SMS links | `sms:+1234567890` | Opens messaging app |
| JavaScript | `javascript:void(0)` | Client-side only |
| Anchors | `#section-name` | Same-page navigation |
| Data URIs | `data:image/png;base64,...` | Embedded content |
| Unsubscribe links | Links with `unsubscribe` in URL | Preserve direct access |

## Bot Detection

Security scanners and link preview features can click links before humans do. Lettermint detects these automated clicks to ensure accurate analytics.

## Webhook Payload

When a human-countable click is detected, Lettermint sends a `message.clicked` webhook event. Machine, link preview, and security scanner clicks are excluded by default and are only sent to webhooks with **Include machine events** enabled.

```json
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567892",
  "event": "message.clicked",
  "timestamp": "2025-08-08T20:18:30.000Z",
  "data": {
    "message_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "subject": "Your weekly recommendations",
    "metadata": {
      "X-Campaign-ID": "weekly-recs"
    },
    "tag": "recommendations",
    "recipient": "user@example.com",
    "clicked_at": "2025-08-08T20:18:30+00:00",
    "destination_url": "https://example.com/product/123",
    "link_index": 0,
    "anchor_text": "View Product",
    "first_click": true,
    "device_type": "mobile",
    "client_type": "browser",
    "client_name": "Safari",
    "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)...",
    "bot": {
      "detected": false,
      "probability": 0,
      "classification": "genuine",
      "proxy_type": null,
      "reason_codes": [],
      "machine": false,
      "counts_for_metrics": true
    }
  }
}
```

**Click-specific fields:**
- `destination_url` - The original destination URL that was clicked
- `link_index` - Zero-based index of the link in the email (order of appearance)
- `anchor_text` - The visible text of the clicked link
- `clicked_at` - Timestamp when the click occurred

**Engagement fields:**
- `first_click` - `true` if this is the first time this recipient clicked any link in this email
- `device_type` - Device category: `desktop`, `mobile`, or `tablet`
- `client_type` - Client category: `browser`, `email_client`, etc.
- `client_name` - Specific client name: `Chrome`, `Safari`, `Outlook`, etc.

**Bot detection fields:**
- `bot.detected` - `true` if the click appears automated
- `bot.probability` - Confidence score from 0-100 (higher = more likely a bot)
- `bot.classification` - Source classification such as `genuine`, `privacy_proxy`, `security_scanner`, or `generic_bot`
- `bot.proxy_type` - Known proxy family when applicable, otherwise `null`
- `bot.reason_codes` - Machine-readable reasons behind the classification
- `bot.machine` - `true` when the click is classified as machine, preview, or security activity
- `bot.counts_for_metrics` - Whether the click contributes to default engagement metrics

See [Bot Detection Field Values](/platform/emails/tracking/introduction#bot-detection-field-values) for `classification` and `proxy_type` values, plus `reason_codes` guidance.

## Limitations

### Token Expiration

Tracking tokens expire **30 days** after the email is sent. After expiration:
- Clicks are not recorded
- Recipients are still redirected to the original URL (graceful degradation)

### Corporate Security Pre-clicking

Some corporate email security tools pre-click all links in emails to scan for malware. Lettermint excludes identified security scanner clicks from default metrics and webhooks. They remain available to opted-in webhooks and reporting requests that include machine activity.

### Plain Text Emails

Click tracking only works for HTML emails. Links in plain-text email parts are not rewritten.

### Link Appearance

The tracking URL is visible if recipients hover over links or inspect the email source. This is standard for email tracking and does not affect the user experience. For a more branded appearance, consider using a [custom tracking domain](/platform/emails/tracking/custom-domains).

## Best Practices

1. **Track specific campaigns** - Use metadata and tags to attribute clicks to campaigns
2. **Monitor unique clicks** - Use `first_click` to distinguish initial engagement from repeat clicks
3. **Test your links** - Send test emails to verify tracked links redirect correctly
4. **Respect privacy** - Disclose tracking in your privacy policy

## Next Steps

- [**Open Tracking**](/platform/emails/tracking/open-tracking) - Combine with open tracking for complete engagement data
- [**Webhook Events**](/platform/webhooks/events) - Full payload reference for all tracking events
- [**Tags**](/platform/emails/tags) - Organize and filter your tracked emails
