# Tracking Referrals

For Fuul to attribute conversions to the right referrer, your app must send two tracking events: **`pageview`** and **`connect_wallet`** (via `identifyUser`).

{% hint style="info" %}
These events require the `send:tracking_event` API key. See [API Key Management](/developer-guide/api-key-management.md).
{% endhint %}

## How attribution works

```
User clicks referral link → pageview event → user connects wallet → identifyUser event
                                   ↓                                        ↓
                         Captures referrer info                Links wallet to tracking session
                                   ↓                                        ↓
                            Later, user converts → Fuul attributes conversion to the referrer
```

## 1. Send pageview

Call `sendPageview` on every page load. The SDK automatically captures the referrer's affiliate code from the URL (`?af=code`, or the legacy `?referrer=code`) and stores a tracking ID in localStorage.

```typescript
import { Fuul } from '@fuul/sdk';

await Fuul.sendPageview();
```

{% hint style="info" %}
The SDK reads referral parameters from the URL automatically. You don't need to persist them when navigating between pages.
{% endhint %}

## 2. Identify the user

Call `identifyUser` every time a user connects a wallet or logs in — including when they switch wallets during a session. This sends a `connect_wallet` event that links their identity to the tracking session.

```typescript
import { Fuul } from '@fuul/sdk';

await Fuul.identifyUser({
  identifier: '0x1234...',
  identifierType: 'evm_address', // evm_address | solana_address | xrpl_address | sui_address | email
  signature: '0xabc...',
  message: 'Sign to verify your identity',
});
```

### Smart contract wallets

For smart contract wallets (EIP-1271), add the `accountChainId` parameter:

```typescript
await Fuul.identifyUser({
  identifier: '0x1234...',
  identifierType: 'evm_address',
  signature: '0xabc...',
  message: 'Sign to verify your identity',
  accountChainId: 1, // Chain ID where the smart contract wallet is deployed
});
```

Supported chains for smart contract wallets:

| Network    | Chain ID |
| ---------- | -------- |
| Ethereum   | 1        |
| Arbitrum   | 42161    |
| Optimism   | 10       |
| Base       | 8453     |
| Polygon    | 137      |
| zkSync Era | 324      |
| BNB Chain  | 56       |
| Avalanche  | 43114    |
| Mode       | 34443    |
| Abstract   | 2741     |
| Bob        | 60808    |
| Berachain  | 80094    |

### XRPL signatures

For XRPL wallets, include the `signaturePublicKey`:

```typescript
await Fuul.identifyUser({
  identifier: 'rAddress...',
  identifierType: 'xrpl_address',
  signature: '0xabc...',
  signaturePublicKey: '0x1234...',
  message: 'Sign to verify your identity',
});
```

## Sending identifyUser from the backend

If you identify users server-side, send the `connect_wallet` event via the REST API. You'll need the `tracking_id` from the browser's `localStorage` (key: `fuul.tracking_id`) — it must match the one sent in the pageview event.

```python
import requests

url = "https://api.fuul.xyz/api/v1/events"

payload = {
    "metadata": {
        "tracking_id": "trackingId123"
    },
    "name": "connect_wallet",
    "user": {
        "identifier": "0x1234...",
        "identifier_type": "evm_address"
    },
    "signature": "0xabc...",
    "signature_message": "Sign to verify your identity",
    "account_chain_id": 1  # Only for smart contract wallets
}

headers = {
    "content-type": "application/json",
    "authorization": "Bearer your-api-key"
}

response = requests.post(url, json=payload, headers=headers)
```

**cURL:**

```bash
curl -X POST https://api.fuul.xyz/api/v1/events \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-api-key" \
  -d '{
    "metadata": { "tracking_id": "trackingId123" },
    "name": "connect_wallet",
    "user": {
      "identifier": "0x1234...",
      "identifier_type": "evm_address"
    },
    "signature": "0xabc...",
    "signature_message": "Sign to verify your identity"
  }'
```

## Signature types

Fuul supports two signature verification methods:

| Type                 | Verification                                                                 | Use case                |
| -------------------- | ---------------------------------------------------------------------------- | ----------------------- |
| Regular message      | [Viem verifyMessage](https://viem.sh/docs/actions/public/verifyMessage.html) | Standard EOA wallets    |
| Typed data (EIP-712) | [Viem verifyTypedData](https://viem.sh/docs/actions/public/verifyTypedData)  | Structured data signing |

For typed data signatures, stringify the typed data object:

```typescript
import { Fuul } from '@fuul/sdk';

const typedData = { address, domain, types, primaryType, message };

await Fuul.identifyUser({
  identifier: '0x1234...',
  identifierType: 'evm_address',
  message: JSON.stringify(typedData),
  signature: '0xabc...',
});
```

{% hint style="info" %}
Requiring users to sign a message ensures event validity and prevents attribution fraud. This is mandatory.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fuul.xyz/developer-guide/tracking-referrals-in-your-app.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
