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.
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.
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>
);
}