The DEX Analytics Problem
Building analytics for a decentralised exchange is harder than it sounds. You have no accounts, no logins, no cookies. Users are pseudonymous wallet addresses. Traditional analytics tools like Google Analytics track page visits but know nothing about blockchain activity.
We needed to answer: How many wallets are connecting? What are they doing? Which pages drive trading?
Here is how we built it.
The Architecture
1. Frontend: useAnalytics Hook
We wrote a lightweight React hook that fires events to our backend:
export function useAnalytics() {
const { address } = useAccount(); // wagmi
const track = useCallback((event, metadata = {}) => {
fetch("/api/analytics/track", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
event,
wallet: address || null,
page: window.location.pathname,
metadata,
}),
keepalive: true, // fire-and-forget, never blocks UI
}).catch(() => {});
}, [address]);
return { track };
}
Key design decision: fire-and-forget. The keepalive: true flag means the request completes even if the user navigates away. We never await it — the UI never waits for analytics.
2. Automatic Tracking in App.jsx
We added two invisible components at the router root:
function PageTracker() {
const { pathname } = useLocation();
const { track } = useAnalytics();
useEffect(() => {
track("page_view", { page: pathname });
}, [pathname]);
return null;
}
function WalletTracker() {
const { address, isConnected } = useAccount();
const { track } = useAnalytics();
const prevAddress = useRef(null);
useEffect(() => {
if (isConnected && address && address !== prevAddress.current) {
prevAddress.current = address;
track("wallet_connect", { wallet: address });
}
}, [isConnected, address]);
return null;
}
Every page visit and every wallet connection is tracked automatically — without touching any individual component.
3. Backend: Redis Storage
The /api/analytics/track endpoint writes to Redis:
// Unique wallets (set — no duplicates)
await cache.sadd("analytics:wallets:all", addr);
await cache.sadd(`analytics:wallets:daily:${day}`, addr);
// Event counters
await cache.incr(`analytics:total:${event}`);
await cache.incr(`analytics:daily:${day}:${event}`);
// Page view counter
await cache.incr(`analytics:pages:${page}`);
No SQL. No third-party service. No data leaving our server. Redis SADD naturally deduplicates wallet addresses across page reloads.
4. The Dashboard
/analytics on 999dex.com now shows:
- Total unique wallets ever connected
- Daily Active Users (DAU)
- New wallets today
- 7-day DAU bar chart
- All-time action counts per feature
- Top pages by visit count
What We Track
| Event | Trigger |
|---|---|
page_view |
Any page navigation |
wallet_connect |
First wallet connection per session |
trade_buy |
Confirmed bonding curve buy |
trade_sell |
Confirmed bonding curve sell |
token_create |
New token deployed |
stake |
$999 staked |
studio_deploy |
Contract deployed via Studio |
Privacy
Wallet addresses are public on-chain — they are not personally identifiable by themselves. We store no IP addresses, no email, no device fingerprint. The only identifier is the wallet address the user chose to connect.
The Result
Within 24 hours of launch, we could see exactly which pages users were hitting, which wallets were new, and where in the funnel users were dropping off. This kind of insight is normally only available to centralised platforms.
Decentralised does not have to mean blind.
Platform: 999dex.com · BlockDAG Mainnet (Chain 1404)
Top comments (0)