Prefer to chat? Query the API with natural language using our AI Skill →

Give your AI tool live Cito endpoint context before you write integration code.

Open AI Skill

Public docs assistant

Tell Cito API what you are building.

Get endpoint recommendations, exact requests, code snippets, and a free-key CTA without digging through every page.

Guides/Player Statistics Dashboard

Player Statistics Dashboard

Build a player stats dashboard with charts and trends

Fetching Player Data

api/player.ts
const API_BASE = "https://api.citoapi.com/api/v1";

async function citoGet(path: string) {
  const response = await fetch(`${API_BASE}${path}`, {
    headers: { "x-api-key": process.env.CITO_API_KEY! }
  });

  if (!response.ok) throw new Error(`Cito API error: ${response.status}`);
  return response.json();
}

export async function getPlayer(username: string, game: string) {
  return citoGet(`/${game}/players/${encodeURIComponent(username)}`);
}

export async function getPlayerHistory(username: string, game: string) {
  return citoGet(`/${game}/players/${encodeURIComponent(username)}/matches?limit=50&sort=desc`);
}

Dashboard Component

PlayerDashboard.tsx
import { useQuery } from '@tanstack/react-query';
import { LineChart, Line, XAxis, YAxis, Tooltip } from 'recharts';

export function PlayerDashboard({ username, game }) {
  const { data: player, isLoading } = useQuery({
    queryKey: ['player', username, game],
    queryFn: () => getPlayer(username, game)
  });

  const { data: history } = useQuery({
    queryKey: ['player-history', username, game],
    queryFn: () => getPlayerHistory(username, game)
  });

  if (isLoading) return <Skeleton />;

  const kdTrend = history?.map(match => ({
    date: new Date(match.played_at).toLocaleDateString(),
    kd: match.eliminations / Math.max(match.deaths, 1)
  }));

  return (
    <div className="space-y-6">
      {/* Player Header */}
      <div className="flex items-center gap-4">
        <Avatar username={player.username} />
        <div>
          <h1 className="text-2xl font-bold">{player.username}</h1>
          <p className="text-muted">{player.team || 'Free Agent'}</p>
        </div>
      </div>

      {/* Stats Grid */}
      <div className="grid grid-cols-4 gap-4">
        <StatCard label="Wins" value={player.stats.career.wins} />
        <StatCard label="K/D" value={player.stats.career.kd_ratio.toFixed(2)} />
        <StatCard label="Win Rate" value={`${player.stats.career.win_rate}%`} />
        <StatCard label="Earnings" value={`$${player.stats.competitive.earnings.toLocaleString()}`} />
      </div>

      {/* K/D Trend Chart */}
      <div className="p-4 bg-secondary rounded-lg">
        <h3 className="font-semibold mb-4">K/D Trend (Last 50 Games)</h3>
        <LineChart width={600} height={200} data={kdTrend}>
          <XAxis dataKey="date" />
          <YAxis />
          <Tooltip />
          <Line type="monotone" dataKey="kd" stroke="#00E5CC" />
        </LineChart>
      </div>

      {/* Recent Matches */}
      <div>
        <h3 className="font-semibold mb-4">Recent Matches</h3>
        <MatchList matches={history?.slice(0, 10)} />
      </div>
    </div>
  );
}

Caching Strategies

Player stats don't change frequently. Use aggressive caching:

// Next.js API route with caching
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const username = searchParams.get('username');

  const data = await getPlayer(username);

  return Response.json(data, {
    headers: {
      'Cache-Control': 'public, s-maxage=300, stale-while-revalidate=600'
    }
  });
}

// React Query with stale time
const { data } = useQuery({
  queryKey: ['player', username],
  queryFn: () => getPlayer(username),
  staleTime: 5 * 60 * 1000, // 5 minutes
  cacheTime: 30 * 60 * 1000 // 30 minutes
});

Player Comparison

export function PlayerComparison({ players }: { players: string[] }) {
  const queries = useQueries({
    queries: players.map(username => ({
      queryKey: ['player', username],
      queryFn: () => getPlayer(username)
    }))
  });

  const data = queries.map(q => q.data).filter(Boolean);

  return (
    <table>
      <thead>
        <tr>
          <th>Stat</th>
          {data.map(p => <th key={p.username}>{p.username}</th>)}
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Wins</td>
          {data.map(p => <td key={p.username}>{p.stats.career.wins}</td>)}
        </tr>
        <tr>
          <td>K/D</td>
          {data.map(p => <td key={p.username}>{p.stats.career.kd_ratio.toFixed(2)}</td>)}
        </tr>
        {/* More stats... */}
      </tbody>
    </table>
  );
}