leaderboards.topBuyers()
Get users ranked by purchase volume within a specified time period.
Signature
leaderboards.topBuyers(query?: LeaderboardPeriodQuery): Promise<LeaderboardResponse<TopBuyer>>Parameters
query (optional)
- Type:
LeaderboardPeriodQuery
interface LeaderboardPeriodQuery {
page_size?: number; // Results per page (default: 20)
period?: '1d' | '7d' | '30d' | 'all'; // Time period (default: 'all')
}Returns
- Type:
Promise<LeaderboardResponse<TopBuyer>>
interface TopBuyer {
rank: string;
user_id: string;
username?: string | null;
wallet_address: string;
total_purchases: string;
total_spent: string;
unique_entries_purchased: string;
unique_feeds_purchased_from: string;
joined_at: number;
}Usage
Basic Example
const topBuyers = await grapevine.leaderboards.topBuyers();
topBuyers.data.forEach(buyer => {
console.log(`#${buyer.rank}: ${buyer.username || buyer.wallet_address}`);
console.log(` Spent: ${formatUSDC(buyer.total_spent)}`);
console.log(` Purchases: ${buyer.total_purchases}`);
});
function formatUSDC(weiAmount: string): string {
const usdc = Number(BigInt(weiAmount)) / 1e6;
return `${usdc.toLocaleString('en-US', { minimumFractionDigits: 2 })}`;
}Filter by Period
// Most active buyers this month
const monthlyBuyers = await grapevine.leaderboards.topBuyers({
period: '30d',
page_size: 10
});
console.log('Top buyers this month:');
monthlyBuyers.data.forEach((buyer, i) => {
const name = buyer.username || `${buyer.wallet_address.slice(0, 8)}...`;
console.log(`${i + 1}. ${name}: ${formatUSDC(buyer.total_spent)}`);
});Buyer Profile Card
function TopBuyerCard({ buyer }: { buyer: TopBuyer }) {
return (
<div className="buyer-card">
<div className="rank">#{buyer.rank}</div>
<h3>{buyer.username || 'Anonymous Collector'}</h3>
<p className="wallet">{buyer.wallet_address.slice(0, 8)}...</p>
<div className="stats">
<div className="stat">
<span className="value">{formatUSDC(buyer.total_spent)}</span>
<span className="label">Total Spent</span>
</div>
<div className="stat">
<span className="value">{buyer.total_purchases}</span>
<span className="label">Purchases</span>
</div>
<div className="stat">
<span className="value">{buyer.unique_entries_purchased}</span>
<span className="label">Entries</span>
</div>
<div className="stat">
<span className="value">{buyer.unique_feeds_purchased_from}</span>
<span className="label">Feeds</span>
</div>
</div>
<p className="member-since">
Member since {new Date(buyer.joined_at * 1000).toLocaleDateString()}
</p>
</div>
);
}Analyze Buyer Behavior
async function getBuyerAnalytics() {
const buyers = await grapevine.leaderboards.topBuyers({ page_size: 100 });
const totalSpent = buyers.data.reduce(
(sum, b) => sum + BigInt(b.total_spent),
BigInt(0)
);
const avgSpent = totalSpent / BigInt(buyers.data.length);
const avgPurchases = buyers.data.reduce(
(sum, b) => sum + parseInt(b.total_purchases),
0
) / buyers.data.length;
const avgFeedsPerBuyer = buyers.data.reduce(
(sum, b) => sum + parseInt(b.unique_feeds_purchased_from),
0
) / buyers.data.length;
return {
topBuyersCount: buyers.data.length,
totalSpent: formatUSDC(totalSpent.toString()),
avgSpentPerBuyer: formatUSDC(avgSpent.toString()),
avgPurchasesPerBuyer: avgPurchases.toFixed(1),
avgFeedsPerBuyer: avgFeedsPerBuyer.toFixed(1)
};
}Find Your Ranking
async function getMyBuyerRank(walletAddress: string) {
const buyers = await grapevine.leaderboards.topBuyers({ page_size: 100 });
const myRanking = buyers.data.find(
b => b.wallet_address.toLowerCase() === walletAddress.toLowerCase()
);
if (!myRanking) {
return { ranked: false, message: 'Not in top 100 buyers' };
}
return {
ranked: true,
rank: parseInt(myRanking.rank),
totalSpent: formatUSDC(myRanking.total_spent),
purchases: myRanking.total_purchases,
entriesBought: myRanking.unique_entries_purchased,
feedsExplored: myRanking.unique_feeds_purchased_from
};
}Leaderboard with Tabs
function BuyerLeaderboard() {
const [buyers, setBuyers] = useState<TopBuyer[]>([]);
const [period, setPeriod] = useState<LeaderboardPeriod>('all');
useEffect(() => {
grapevine.leaderboards.topBuyers({ period, page_size: 20 })
.then(result => setBuyers(result.data));
}, [period]);
return (
<div className="leaderboard-container">
<h2>Top Collectors</h2>
<div className="period-tabs">
<button
onClick={() => setPeriod('1d')}
className={period === '1d' ? 'active' : ''}
>
Today
</button>
<button
onClick={() => setPeriod('7d')}
className={period === '7d' ? 'active' : ''}
>
This Week
</button>
<button
onClick={() => setPeriod('30d')}
className={period === '30d' ? 'active' : ''}
>
This Month
</button>
<button
onClick={() => setPeriod('all')}
className={period === 'all' ? 'active' : ''}
>
All Time
</button>
</div>
<div className="buyers-list">
{buyers.map(buyer => (
<div key={buyer.user_id} className="buyer-row">
<span className="rank">#{buyer.rank}</span>
<div className="info">
<span className="name">
{buyer.username || `${buyer.wallet_address.slice(0, 10)}...`}
</span>
<span className="stats">
{buyer.total_purchases} purchases • {buyer.unique_feeds_purchased_from} feeds
</span>
</div>
<span className="spent">{formatUSDC(buyer.total_spent)}</span>
</div>
))}
</div>
</div>
);
}Notes
- Authentication: Not required - public endpoint
- Ranking: Ordered by total amount spent (highest first)
- Period: Filters purchases made within the specified timeframe
Related
- leaderboards.topProviders() - Top content creators
- transactions.list() - View transaction details
- wallets.getStats() - Individual wallet statistics