How to set up Google Tag Manager on a DeFi site (without breaking privacy)
DeFi teams ship analytics last. By the time someone realizes they have zero visibility into where users drop off in the wallet-connect flow, the protocol has been live for 6 months. Here's the GTM setup that captures the 6 events that actually matter, stays privacy-safe, and doesn't leak wallet addresses to ad networks.
Why GTM specifically for DeFi
You could hardcode analytics calls into your frontend. Many DeFi teams do. The problem: changing what you track requires a frontend deploy. With GTM, the data layer goes through one event bus and the tags get configured server-side in the GTM container. Marketing and analytics teams can adjust tracking without engineering deploys.
For DeFi specifically, the bigger value is wallet-event tracking. Wallet connect, transaction signed, transaction confirmed, transaction failed. These events fire from the wallet SDK, not the page. Routing them through GTM means you can fan out to multiple analytics destinations (GA4, Mixpanel, custom warehouse) without 4 separate SDK calls.
The catch: DeFi has serious privacy requirements that mainstream e-commerce doesn't. Wallet addresses are pseudo-PII. Transaction hashes can be correlated against on-chain data. Default GTM behavior often leaks both. Setup correctly or not at all.
The 6 events every DeFi protocol should track
Track these six events. Everything else is noise.
1. wallet_connect_attempted. User clicked the Connect Wallet button. Fires before the wallet dialog opens. This event captures intent.
2. wallet_connect_succeeded. User completed the wallet connection. Wallet provider name is fine to capture (MetaMask, Phantom, etc). Wallet address is NOT.
3. wallet_connect_failed. User cancelled or the wallet rejected. Capture the rejection reason if exposed by the wallet SDK.
4. transaction_submitted. User signed and submitted a transaction. Capture the transaction type (swap, stake, mint, etc) and the protocol contract involved (not the user's wallet).
5. transaction_confirmed. Transaction confirmed on-chain. Don't poll for this — listen to the wallet SDK's confirmation event.
6. transaction_failed. Transaction reverted on-chain. Capture the revert reason if available. This is the most diagnostic event for fixing UX problems.
That's the entire tracking plan. Resist the urge to add page_view, click, scroll. GA4 captures those by default. Adding more custom events dilutes the signal of the 6 events that actually matter for product decisions.
Wallet connect event setup
Push to the data layer from your wallet-connect handler:
// On user clicks Connect Wallet
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'wallet_connect_attempted',
wallet_provider: 'metamask', // detected from wallet SDK
});
// On wallet connection success
window.dataLayer.push({
event: 'wallet_connect_succeeded',
wallet_provider: 'metamask',
chain_id: 1, // human-readable chain, not wallet address
// DO NOT push wallet_address here
});In GTM, create three triggers (one per event) and three tags (one per destination). Each tag fires when its trigger sees the matching dataLayer event.
For GA4, the event name maps 1:1. For Mixpanel, send the same event name plus the wallet_provider and chain_id as properties. Avoid sending the same event 4 times to 4 destinations from the page directly — fan out through GTM instead.
Transaction event tracking
Transaction events fire after the user signs. The data layer push needs to capture protocol-side context, not user-side.
// On transaction submission (after wallet signs)
window.dataLayer.push({
event: 'transaction_submitted',
transaction_type: 'swap', // swap, stake, claim, mint, etc.
protocol_contract: '0xA0b8...', // your contract
amount_usd_bucket: '100-1000', // bucket, not exact amount
chain_id: 1,
// NEVER push: from_address, transaction_hash, exact USD amount
});The amount_usd_bucket pattern is critical. Exact transaction values are pseudo-PII when combined with timestamp — they can identify users. Bucket the value: under-100, 100-1000, 1000-10000, over-10000. This is enough resolution for product decisions and removes the privacy concern.
Same approach for transaction_confirmed and transaction_failed. Track that it happened, what type, what bucket, and on which chain. Skip the rest.
Privacy rules: never send these to GTM
Six things to never push to the data layer or send through GTM. If you're sending any of these, your DeFi analytics is a privacy liability.
1. Wallet addresses. Pseudo-PII. Correlatable to real identities through on-chain analysis services.
2. Transaction hashes. Public on-chain but combining them with user-agent and timestamp in your analytics database creates a re-identification vector.
3. Exact transaction USD values. Bucket instead.
4. ENS names. Some users use their real names as ENS. Treat as PII.
5. User-set referral codes. Often contain identifiable usernames.
6. Email addresses from optional newsletter signups. Send those directly to your email tool, not through GTM where ad-network tags can scrape them.
Consent Mode integration
Google Consent Mode v2 is required for sites serving EU users. GTM has native support. You configure each tag with consent requirements, and the tag holds firing until the user grants the required consent type.
For the 6 DeFi events: analytics_storage consent for the GA4 destination, ad_storage consent if you're sending to advertising platforms (most DeFi protocols don't), and personalization_storage for any user-segmentation tagging.
The consent banner integrates with GTM by pushing consent state to the data layer when the user makes a choice. Use a CMP that supports Consent Mode v2 natively (Cookiebot, OneTrust, Iubenda). Don't roll your own banner — getting Consent Mode right by hand is harder than picking a vendor.
Server-side GTM is the next upgrade for privacy-serious DeFi sites. It moves tag execution to a Google Cloud container you control, which means raw data goes to your server first and you decide what to forward. Worth the setup time if you're handling EU users at scale or have a real CISO function.
Common questions
Do I need GTM if I have GA4 hardcoded?
Not strictly. GTM adds flexibility for non-engineering teams to adjust tracking. If your team is small and tracking rarely changes, hardcoded GA4 plus the wallet event bus is fine.
Can wallet addresses be sent to GA4 if I hash them?
Hashing helps but doesn't fully solve it. Sufficient hashing (proper salt, server-side) is OK. Client-side SHA-256 of a wallet address is still effectively pseudo-PII because the input space is enumerable.
What if my DeFi site has 0 EU users?
Compliance still matters. Some US states (California, Virginia, Colorado) have privacy laws that mirror GDPR's analytics consent rules. Consent Mode is good practice everywhere now.
Should I use server-side GTM?
Worth it if you have over 100K monthly users or any EU/UK regulated traffic. Below that, client-side GTM with Consent Mode is sufficient.
How do I verify GTM isn't leaking wallet addresses?
Browser dev tools network tab. Filter for googletagmanager.com or google-analytics.com requests. Inspect each request's payload. If you see anything that looks like a wallet address or transaction hash, something is misconfigured.
Audit your crypto site in 60 seconds
8-module deep scan. AI visibility, schema, technical SEO, backlinks. One domain free forever.
