BrawlVision

Methodology

How we build every stat you see

BrawlVision combines Supercell's official API, our own PRO-player sampling layer and several statistical smoothing steps to give you numbers that are stable, comparable, and honest about their own uncertainty. This page documents each of those steps, with the exact formulas and update cadences.

Last updated: 2026-04-30

Data sources

Everything we display comes from three sources we keep auditable: Supercell's public API (developer.brawlstars.com), the Brawlify CDN (cdn.brawlify.com), and our own Supabase database, which persists battles and aggregates that the official API doesn't expose past the last 25 matches per player.

Supercell's API is the canonical source for structural data — brawlers, gadgets, star powers, hypercharges, gears and event rotation — but it leaves out critical fields like brawler images, rarity, and long descriptions. We cross-reference those with the Brawlify CDN, which operates independently and sometimes lags Supercell by one to three days. When we detect a new brawler on the official API that doesn't exist on Brawlify yet, we keep a local rarity map (BRAWLER_RARITY_MAP) so the brawler's page renders correctly on launch day.

Our database stores two classes of rows in the meta_stats table: source=user (real battles from premium users who enabled sync) and source=global (automated sampling from the top PRO leaderboards). Every public statistic on the site is computed filtering by source=global, so personal data from any single user never leaks into public pages.

How we build the PRO data

The "PRO" layer of BrawlVision is a set of aggregates computed over recent battles from the world's top players. Every six hours a cron job (meta-poll) queries Supercell's official rankings for eleven countries — the ones that concentrate competitive activity — and builds a deduplicated pool of roughly 2,100 unique players from each top 200.

Over that pool we apply a probabilistic sampler to keep popular (map, mode) combinations from dominating the dataset and masking the rare ones. The probability of accepting an individual battle is p = min(1, (minLive + 1) / (current + 1)), where minLive is the count for the least-represented combination and current is the count for the candidate battle's combination. Under-sampled combinations get higher acceptance; saturated ones stop growing.

The cron iterates up to META_POLL_MAX_DEPTH = 1,000 players per run with a soft 270-second budget so it stays inside the serverless function's 300-second maxDuration. Each response includes an "adaptive" diagnostic block with iteration counts, players sampled, and per-mode counts, so any anomalous sampler behavior is observable in production.

Bayesian Win Rate

Naive Win Rate (wins / matches) is misleading on small samples: a brawler going 3-0 on a new map shows "100 % WR" without that meaning anything. BrawlVision uses Bayesian smoothing to correct that and return a number that is comparable across brawlers with very different sample sizes.

The formula is WR_bayesian = (wins + α) / (battles + α + β), where α and β are hyperparameters encoding a 50 %-WR prior. In practice α = β = 25, equivalent to "assume 50 prior battles split 50/50 before seeing real data". A brawler with 3 wins and 0 losses goes from naive 100 % to (3 + 25) / (3 + 50) = 52.8 %, much more representative of the actual sampling state.

As the sample grows, the prior's weight decays: with 1,000 battles and 530 wins, the Bayesian WR sits at (530 + 25) / (1,000 + 50) = 52.9 %, essentially identical to the naive 53.0 %. Smoothing only "hurts" when the sample is genuinely small. That is exactly the desired property: penalize noise, not signal.

Comfort Score

Comfort Score is BrawlVision's in-house metric answering the question "which brawler are you actually better with than with average?". It is not a raw Win Rate: it combines three components with weights 60/30/10 to cover different dimensions of personal performance.

The main component (60 %) is the player's WR with that brawler, Bayesian-smoothed exactly like the global meta, so a rarely-played brawler doesn't game the ranking. The middle component (30 %) is the difference between that personal WR and the brawler's overall meta WR: a player at 55 % on SHELLY when the global meta sits at 48 % earns more comfort than someone at 55 % on a brawler whose meta is 53 %, because the relative lift is bigger.

The final component (10 %) is normalized usage frequency: all else equal, playing a brawler 100 times counts more than playing it 10, because consistency is rewarded. The exact formulas and weights live in src/lib/analytics/compute.ts and apply identically on every endpoint call, so the ranking is reproducible.

Update cadence

How often a piece of data refreshes affects how you should interpret it, so we document it explicitly. Static pages (this one included) use ISR (Incremental Static Regeneration) with a 24-hour revalidation. Pages with dynamic data cache the API response until the relevant job invalidates it.

Brawlers, gadgets and star powers sync from the Supercell API with a 24-hour server cache. The meta-poll (PRO data) runs every 6 hours and produces fresh meta_stats rows. The 7-day trend precomputation runs in pg_cron at "17 */6 * * *" (minute 17 of every sixth hour) to avoid colliding with the meta-poll. The in-game event rotation refreshes every 30 minutes.

Individual battles from premium users who enabled sync are downloaded right after each match in a moving window via the sync cron. Once in our database they feed meta_stats with source=user and are the basis for private analytics in the profile section; they never appear in public aggregates and never mix with source=global.

Frequently asked questions

Why isn't a brawler's WR 0 % or 100 % on small samples?+

Because we apply Bayesian smoothing with a 50 %-centered prior. With very few matches the displayed number sits close to 50 %; as the sample grows, it converges to the real WR. This is deliberate: 100 % on 3 matches is not information, it is noise.

Do public pages use data from real users?+

No. Every public aggregate filters by source=global, which only holds battles taken from automated PRO-leaderboard sampling. Private battles from premium users are stored with source=user and never cross into public pages.

What happens when Supercell ships a new brawler?+

The brawler list comes from the official API, so the full roster appears on the site the same day as the launch. Rarity and images come from Brawlify, which can lag by one to three days; we keep a local rarity map (BRAWLER_RARITY_MAP) as fallback for those first days.

Why do some trends show a dash instead of a percentage?+

We only show the trend if each half of the 14-day window has at least 3 battles in source=global. When a brawler is rarely seen, we prefer to show nothing rather than a low-signal number.

Does the site use AI to generate descriptions?+

Descriptions are generated dynamically from our own data (best map, best mode, Bayesian WR per brawler). We do not copy text from Brawlify or the wiki, and we do not use language models to inflate content.

Questions or corrections?

If you spot a methodological error or want to suggest an improvement, get in touch. We keep this page in sync with every relevant change to how we compute the data.