Live

Screener

Rank every indexed wallet on expected value per dollar rather than win rate, filter on any column, and call the same screen from the API.

The screener ranks every indexed wallet on a statistic that prices in the odds each wallet paid. By the end of this page you will know which column to sort on, which columns are deliberately unsortable, how to shape a screen with bounds and filters, and how to fetch the same screen from GET /api/v1/screener.

How the ranking works

Six columns carry the V5 skill statistics. They are computed per wallet from resolved outcomes and refreshed by the stats pipeline.

ColumnParamWhat it answers
EV lower confidence boundev_ci_lowHow much edge survives the sample. The default ranking column for skill.
EV per dollarev_per_dollarPoint estimate of edge per dollar staked.
EV per dollar (decayed)ev_decayedSame, with recent trades weighted more heavily.
Skill q-value (FDR)skill_qvalueFalse-discovery-rate q-value. Lower is stronger. Sort ascending.
Effective sample sizeeffective_nThe sample after correlated trades on one event are collapsed.
Skill z (recency-decayed)z_decayedDecayed z-score, clustered by event.

Two properties are worth stating explicitly because they change how you read a board:

  • z-scores are clustered by event. Twenty positions on one election are one observation, not twenty. That is what effective_n reports, and it is why a wallet with 400 trades can carry an effective n in the dozens.
  • q-values, not p-values. Scoring three million wallets produces thousands of p < 0.01 wallets by chance alone. The q-value is the false-discovery rate at that threshold, so a q-value of 0.05 means roughly one in twenty wallets at or below it is noise.

Win rate filters, but never sorts

Win rate ignores the price paid, and on a prediction market the price is the whole game. One wallet in the index settles 6,364 positions at an average entry of 99.6¢: it wins 99.86% of them, earns 0.25¢ per dollar staked, and finishes negative after fees. Another wins 44.3% and makes money, because it buys longshots that resolve. Ranking on win rate sorts the first above the second — the numbers are right and the ordering is a lie.

So bayesian_win_rate and confidence stay visible as columns and stay usable as filters, and the API refuses them as a sort key:

400 Bad Request
{
"error": {
  "code": "bad_request",
  "message": "bayesian_win_rate cannot be a sort key. Ignores entry price — 99% win rates are usually 99c entries. Rank by EV lower bound instead.",
  "request_id": "req_..."
}
}

A bound is a claim about one wallet; a sort is a claim that one wallet beats another. The first is fine on win rate, the second is not.

Columns

Every column below can be requested with columns=, bounded with min_<column> / max_<column>, and — unless noted — used as sort=.

ParamLabelSortable
pnlProfit (canonical)yes
polymarket_pnlProfit (Polymarket-reported)yes
ledger_pnlProfit (our ledger)yes
total_volumeVolumeyes
avg_bet_sizeAverage bet sizeyes
bayesian_win_rateWin rate (shrunk)filter only
confidenceWin-rate confidencefilter only
resolved_betsResolved betsyes
total_betsTotal betsyes
markets_tradedMarkets tradedyes
z_decayedSkill z (recency-decayed)yes
ev_per_dollarEV per dollaryes
ev_ci_lowEV lower confidence boundyes
ev_decayedEV per dollar (decayed)yes
effective_nEffective sample sizeyes
skill_qvalueSkill q-value (FDR)yes
markout_1hMarkout 1hyes, but unpopulated
markout_24hMarkout 24hyes, but unpopulated
last_active_atLast fillyes
last_updatedStats refreshedyes

pnl is the canonical profit column: Polymarket's reported figure when one exists, our own ledger otherwise. polymarket_pnl and ledger_pnl expose the two inputs separately so you can compare them yourself.

The default sort is pnl descending, and the default columns are pnl, total_volume, bayesian_win_rate, confidence, resolved_bets, markets_traded, last_active_at.

Columns with no writer yet

markout_1h and markout_24h are in the catalog but no pipeline populates them yet. Sorting or filtering on one returns an empty page, which is a missing pipeline rather than a missing population — so the response names them:

json
"empty_columns": ["markout_1h"]

Filters

  • trader_kindany, human, bot, maker or unknown. Every wallet carries one verdict: a bot is at least 10,000 lifetime fills across 250 or more markets; a maker earns maker rebates at least five times its taker rebates at machine scale; anything with fills that trips neither rule is human. Filtering to human is the fastest way to drop market makers off a board.
  • active_within24h, 7d or 30d, applied to the wallet's most recent fill. A wallet with no recorded fill fails the filter.
  • min_<column> / max_<column> — numeric bounds on any numeric column, in the column's own units. Combine freely: min_resolved_bets=100 and max_skill_qvalue=0.05 is "at least a hundred resolved bets, and significant after false-discovery correction".

Screens are one string

A screen — sort, direction, filters, bounds, columns, window — encodes into a single state token, versioned with an s1. prefix. The UI and the API share the codec, so a screen you shape in the browser and a screen you call from a script are the same object, and a link you paste to someone reproduces exactly what you were looking at.

Pass it as state=, then override any single field with an ordinary parameter:

http
GET /api/v1/screener?state=<token>&sort=ev_ci_low&dir=desc

Every response echoes the normalized token back as state, so you can capture the screen you actually got rather than the one you thought you asked for.

GET /api/v1/screener

Minimum tier free. Results are cursor-paginated with a keyset cursor, so a page boundary survives the stats refresher rewriting rows underneath you.

GET /api/v1/screener
curl -G "https://crowdintel.xyz/api/v1/screener" \
-H "Authorization: Bearer $CROWDINTEL_KEY" \
--data-urlencode "sort=ev_ci_low" \
--data-urlencode "dir=desc" \
--data-urlencode "trader_kind=human" \
--data-urlencode "min_resolved_bets=100" \
--data-urlencode "max_skill_qvalue=0.05" \
--data-urlencode "columns=pnl,ev_ci_low,skill_qvalue,effective_n,resolved_bets" \
--data-urlencode "limit=25"

The envelope carries the screen's metadata as siblings of data, and every row keys its metrics by the same param name you sorted and filtered on:

200 OK
{
"state": "s1.eyJzIjoiZXZfY2lfbG93Iiwi...",
"sort": "ev_ci_low",
"dir": "desc",
"columns": ["pnl", "ev_ci_low", "skill_qvalue", "effective_n", "resolved_bets"],
"empty_columns": [],
"depth_cap": 25,
"tier": "free",
"data": [
  {
    "address": "0x...",
    "trader_kind": "human",
    "trader_kind_label": "Human",
    "polymarket_name": "...",
    "polymarket_avatar": "https://...",
    "pnl": 412803.11,
    "ev_ci_low": 0.031,
    "skill_qvalue": 0.004,
    "effective_n": 61.4,
    "resolved_bets": 388
  }
],
"next_cursor": "eyJ2Ijo..."
}

Parameters

ParamValuesDefault
stateencoded screen tokennone
sortany sortable column parampnl
dirasc, descdesc
trader_kindany, human, bot, maker, unknownany
active_within24h, 7d, 30dnone
min_<column> / max_<column>numbernone
columnscsv of column paramsthe seven default columns
windowallall
limit1–10025
cursoropaque cursor from next_cursornone

window accepts only all today. Windowed PnL columns are not shipped, and the endpoint returns 400 rather than answering a 7-day question with lifetime numbers.

How deep you can page

depth_cap is how far into the ranking a tier may page, and the cursor carries the depth so the cap survives paging.

TierDepth cap
Free25
Terminal500
Terminal Pro1,000

Every tier sees the same columns and the same ranking; the cap is how far down the board you may walk. At the cap, next_cursor comes back null — a free key gets one page of up to 25 rows and no continuation. Replaying a cursor against a different screen is a 400 rather than a silently different page, so keep the query identical while paging.

Shape the screen with bounds rather than paging to find what you want: min_resolved_bets=100 with max_skill_qvalue=0.05 puts what you were looking for on page one.

Next

Live
Beta
···v0.1.0
CrowdIntel needs a newer browser

Your device is on iOS 15 or older. CrowdIntel uses features (color-mix, WebGL2, modern auth) that require iOS 16+ / Safari 16+.

iPhone 7 maxes out at iOS 15, so the site can't render here. Open CrowdIntel on a desktop browser or a newer phone.

crowdintel.xyz

◆ legacy browser fallback