Skip to content

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