Documentation Index
Fetch the complete documentation index at: https://docs.mobula.io/llms.txt
Use this file to discover all available pages before exploring further.
Building a wallet tracker used to mean writing chain-specific RPC logic for every network, normalizing token decimals, fetching prices separately, and stitching it all together. In 2026, you can skip all of that.
This tutorial shows how to build a fully functional multi-chain wallet tracker in under 10 minutes using the Mobula API — one endpoint, all chains, aggregated PnL included.
What You’ll Build
A CLI wallet tracker that:
- Fetches all token holdings across every chain (EVM + Solana)
- Shows current USD value and 24h PnL per token
- Displays total portfolio value and overall PnL
Time to build: ~10 minutes
Lines of code: ~50
API calls needed: 1
Prerequisites
Step 1: Install the SDK
npm install @mobula_labs/sdk
Step 2: Fetch the Portfolio
import { MobulaClient } from "@mobula_labs/sdk";
const client = new MobulaClient({
apiKey: process.env.MOBULA_API_KEY,
});
async function getWalletPortfolio(address: string) {
const { data } = await client.wallet.portfolio({
wallet: address,
});
return data;
}
That’s the entire data-fetching layer. One call returns balances, prices, and PnL across all chains.
Step 3: Display the Results
async function main() {
const address = process.argv[2];
if (!address) {
console.error("Usage: ts-node tracker.ts <wallet-address>");
process.exit(1);
}
console.log(`\nFetching portfolio for ${address}...\n`);
const portfolio = await getWalletPortfolio(address);
// Total portfolio value
console.log(`Total Value: $${portfolio.total_wallet_balance.toFixed(2)}`);
console.log(`24h PnL: $${portfolio.total_realized_pnl.toFixed(2)}\n`);
// Top holdings
console.log("Holdings:");
console.log("─".repeat(60));
const sorted = portfolio.assets
.filter((a) => a.estimated_balance > 1)
.sort((a, b) => b.estimated_balance - a.estimated_balance)
.slice(0, 20);
for (const asset of sorted) {
const pnl = asset.realized_pnl ?? 0;
const pnlStr = pnl >= 0 ? `+$${pnl.toFixed(2)}` : `-$${Math.abs(pnl).toFixed(2)}`;
console.log(
`${asset.asset.symbol.padEnd(12)} $${asset.estimated_balance.toFixed(2).padStart(12)} ${pnlStr.padStart(12)} ${asset.asset.blockchains?.[0] ?? "unknown"}`
);
}
}
main().catch(console.error);
Step 4: Run It
MOBULA_API_KEY=your_key ts-node tracker.ts 0xYourWalletAddress
Output:
Fetching portfolio for 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045...
Total Value: $4,821,334.12
24h PnL: +$142,891.44
Holdings:
────────────────────────────────────────────────────────────
ETH $2,341,200.00 +$89,200.00 ethereum
USDC $812,450.00 $0.00 base
ARB $234,100.00 +$12,400.00 arbitrum
...
What the API Returns
The /api/2/wallet/portfolio endpoint gives you:
total_wallet_balance — total USD value across all chains
total_realized_pnl — realized PnL since first tracked transaction
assets[] — array of token holdings, each with:
asset.symbol, asset.name, asset.logo
token_balance — raw token amount
estimated_balance — USD value
realized_pnl, unrealized_pnl
asset.blockchains — which chains the token exists on
Add Historical Balance
Want to show a balance chart over time? One more call:
const history = await client.wallet.history({
wallet: address,
from: Date.now() - 30 * 24 * 60 * 60 * 1000, // 30 days
to: Date.now(),
});
// history.data is an array of { timestamp, balance } points
Deploy as an API
Wrap it in a simple Express server:
import express from "express";
const app = express();
app.get("/portfolio/:address", async (req, res) => {
const portfolio = await getWalletPortfolio(req.params.address);
res.json(portfolio);
});
app.listen(3000);
You now have a production-ready multi-chain portfolio API.
Next Steps
- Add DeFi positions —
/api/2/wallet/defi-positions for LP, lending, and staking
- Track new wallets in real-time — subscribe via WebSocket for live balance updates
- Label wallets —
/api/2/wallet/labels returns exchange labels, whale tags, and insider flags
Full API documentation → | SDK on npm →