CS2 Smurf Detection (Faceit)
Smurfing is when a strong player jumps on a new account and farms lower lobbies. This project pulls Faceit CS2 stats and recent matches, then outputs a simple Smurf Score (0–100) with the receipts: per-metric bars and plain-English flags. It’s a lightweight API.
Goal
Build a fast system that helps spot suspicious accounts using real match data.
- Fetch player + match data from Faceit
- Derive a few readable signals
- Combine them into a stable 0–100 score
- Explain the score with flags
Architecture
Nickname → player_id, fetch stats + recent matches, compute features, return JSON.
Frontend
Calls the API and renders score, metrics, flags, and a recent matches table.
Pipeline
GET /api/analyze?player=<nickname>
1) resolve player id
2) fetch lifetime stats (FACEIT CS2)
3) fetch recent matches (last ~20)
4) fetch per-match stats (subset for features)
5) compute signals → score + flags
6) return JSON
Signals
v1 is intentionally boring: a weighted sum of interpretable signals. Boring is good.
• K/D and win rate: dominance signals
• Headshot %: mechanical skill signal
• Win streak: short-term domination
• Recent spike: recent performance above lifetime baseline
Scoring
Each rule adds points. The total is clamped to 0–100. Nothing hidden, nothing mystical.
// sketch
score = 10
if matches_played < 50: score += 25
if kd >= 1.30: score += 30
if win_rate >= 60: score += 20
if headshot_pct >= 55: score += 15
if winstreak >= 5: score += 15
if recent_kd - lifetime_kd >= 0.30: score += 20
score = clamp(score, 0, 100)
Output
The API returns UI-ready JSON: headline score, raw stats, normalized metric bars, and flags that explain the result.
{
"smurf_score": 72,
"win_rate": 61.4,
"kd_ratio": 1.42,
"matches_played": 38,
"metrics": { "headshot": {"raw":"58%","norm":85} },
"flags": [
{"level":"high","title":"Low Match Count","description":"Fresh account + strong stats."}
]
}
How to Read a High Score
• Matches: 38
• Lifetime K/D: 1.42
• Recent K/D spike
• Win streak: 6
Interpretation: small sample + consistent dominance + spike = suspicious.
Validation
- Sanity: legit high-level accounts shouldn’t always score high
- Edge cases: low matches but average stats should stay moderate
- Stability: score shouldn’t swing wildly between runs
- Explainability: flags should match what a human would point at
Visuals
Since v1 is rules, visuals are about insight: score distribution, feature contributions, and recent vs lifetime comparisons.
Wrap-up
This is a practical baseline: fast, cheap, explainable. If it’s wrong, it’s wrong in a way you can actually fix.