Skip to main content

Automatic Attribution on Base

Once your project is registered on Base Dashboard, the Base App will auto-append your Builder Code to transactions its users make in your app (e.g. via your app, or the Base App’s browser). This attributes that activity to your project and qualifies you for potential future rewards.

Integrating Outside the Base App

If users also access your app on the web or through other clients, you’ll need to integrate the dataSuffix parameter to capture that activity. When you register a project on Base Dashboard, you will receive a Builder Code—a random string (e.g., bc_b7k3p9da) that you’ll use to generate your attribution suffix. The recommended approach is to configure dataSuffix at the client level, which appends your Builder Code to all transactions.
You can find your code anytime under Settings → Project Settings → Builder Code. Switch the format to Encoded String to copy the full ERC-8021 suffix, the same hex value Attribution.toDataSuffix returns.

Quick Setup with Wagmi

1

Install Dependencies

Install the required packages. Requires viem version 2.45.0 or higher.
Install Wagmi attribution dependencies
2

Configure Your Wagmi Client

Add the dataSuffix option to your Wagmi config. This automatically appends your Builder Code to all transactions.
config.ts
3

Use Wagmi Hooks as Usual

With the config in place, all transactions automatically include your Builder Code—no changes to your hooks or components. This works with both useSendTransaction and useSendCalls.
App.tsx

Quick Setup with Viem

1

Install Dependencies

Install the required packages. Requires viem version 2.45.0 or higher.
Install Viem attribution dependencies
2

Configure Your Wallet Client

Add the dataSuffix option when creating your wallet client. See the viem wallet client docs for more configuration options.
client.ts
3

Send Transactions as Usual

All transactions sent through this client automatically include your Builder Code.
send-transaction.ts

Using CDP Wallets

Coinbase Developer Platform (CDP) Wallets support Builder Codes on user operations from smart accounts. Pass dataSuffix when you send a user operation so your Builder Code is appended; no contract changes required. This works across the React hooks (useSendUserOperation), Node (TypeScript), and Python SDKs. See Builder Codes in the CDP Wallets documentation for setup instructions, including how to generate the suffix with Attribution.toDataSuffix from ox/erc8021.

Using Privy

Privy provides a dataSuffix plugin that automatically appends your Builder Code to all transactions—including both EOA transactions and ERC-4337 smart wallet user operations. See the Privy Builder Codes integration guide for setup instructions.

Legacy: Per-Transaction Approach

If you need to append the suffix on a per-transaction basis rather than at the client level, you can pass dataSuffix directly to the transaction.
App.tsx

Verify Attribution

To confirm your Builder Code is being appended correctly: 1. Use a Block Explorer (Basescan, Etherscan, etc.)
  • Find your transaction hash
  • View the input data field
  • Verify the last 16 bytes are the 8021 repeating
  • Decode the suffix to confirm your Builder Code is present
2. Open Source Tools
  • Use the Builder Code Validation tool
  • Select transaction type
  • Enter the transaction or UserOperation hash
  • Click the Check Attribution button

Track User Analytics

Builder Codes tell you which onchain transactions came from your app. To measure active users, retention and conversion, join that onchain data with the signals your app already sees when someone opens it, connects a wallet and sends a transaction. This section shows where each signal comes from and how to read it. Where you store the data and which analytics stack you use is up to you.
1

Identify Users by Wallet Address

The connected wallet address is the key that joins in-app activity to onchain activity. Read it from the wallet’s EIP-1193 provider, which every wallet library exposes, and normalize it to lowercase so the same address always matches.
identify-wallet.ts
For smart accounts, this is the smart contract account address. Onchain, it appears as the sender of each UserOperation, not as the from of the outer transaction (see step 3).
2

Capture In-App Signals at Each Journey Stage

Each stage of the funnel has a signal your app can read directly. Store each one with the wallet address and a timestamp.Record the transaction hash and the action it performs in your app (for example, mint, swap or deposit) at submit time. The hash is what links an in-app action to its onchain outcome.
resolve-call-bundle.ts
3

Read Transaction Outcomes Onchain

Onchain data is the source of truth for whether a transaction happened, who sent it and whether it carried your Builder Code. Where each field lives depends on the account type:The ERC-8021 suffix sits at the end of the calldata and reads backwards: the 16-byte marker 0x80218021802180218021802180218021, then a 1-byte schema ID, then a 1-byte length, then the comma-separated codes as ASCII. For example, bc_b7k3p9da produces the suffix 0x62635f62376b33703964610b0080218021802180218021802180218021. Match on the decoded codes rather than the raw bytes, because a wallet can add its own code next to yours.The function below takes a transaction hash recorded in step 2 and returns one row per user action, for both account types. It uses Viem and ox, which are already used on this page; any RPC client works the same way.
get-attributed-activity.ts
To backfill history, or to catch transactions sent outside your app’s UI, scan Base blocks (or your contracts’ logs with eth_getLogs) for calldata that ends with the ERC-8021 marker, and decode each match the same way.
4

Compute the Metrics

Join the in-app signals from step 2 with the onchain rows from step 3 on the lowercased wallet address, and on the transaction hash for the submit and success stages. Then:
  1. Active users: count distinct addresses per UTC day, week or month. Report connected users and transacting users (at least one row with success and attributed both true) separately, since the gap between them is your activation rate.
  2. Retention: assign each address to a cohort by the week of its first successful attributed transaction, then measure the share of each cohort that transacts again 1, 7 and 30 days later.
  3. Funnel: count addresses that reach each stage (open → connect → submit → success), split by acquisition source. Drop-offs between submit and success split into rejected signatures (error code 4001), reverted transactions (success is false) and transactions without your Builder Code (attributed is false), which usually means a client is not configured with dataSuffix.