Take any soccer match. Convert the three moneyline odds to implied probabilities and add them up. You won't get 100%. You'll get 105-110%.
Home 1.90 → 1/1.90 = 52.6%
Draw 3.60 → 1/3.60 = 27.8%
Away 4.20 → 1/4.20 = 23.8%
Sum = 104.2%
That extra 4.2% is the bookmaker's margin — the "vig." It's not a prediction; it's a fee, smeared invisibly across every outcome. If you publish raw implied probabilities in your app, your content quietly inherits it: every team looks a few points more likely to win than the market actually believes.
De-vig in 10 lines
The simplest fix is proportional normalization — divide each implied probability by the sum:
function devig(odds) {
// odds: { home: 1.90, draw: 3.60, away: 4.20 }
const implied = Object.fromEntries(
Object.entries(odds).map(([k, o]) => [k, 1 / o])
);
const sum = Object.values(implied).reduce((a, b) => a + b, 0);
return Object.fromEntries(
Object.entries(implied).map(([k, p]) => [k, p / sum])
);
}
devig({ home: 1.90, draw: 3.60, away: 4.20 });
// → { home: 0.505, draw: 0.267, away: 0.228 } — sums to exactly 1
Now the probabilities are the market's actual opinion, margin removed.
The part that's not 10 lines
One bookmaker's de-vigged line is still one bookmaker's opinion. For a stable number you want the consensus: survey many books, de-vig each, average them — continuously, across every fixture, in every sport you cover. That's a pipeline, not a snippet.
I run that pipeline at SkipOdds: 69+ bookmakers, 13 sports (soccer, NFL, NBA, MLB, NHL, tennis, golf, cricket, rugby, MMA, boxing, college football and basketball), averaged and de-vigged so every response sums to exactly 100%. There's a free demo key you can hit right now:
curl -H "x-api-key: skipodds-demo-2026" \
"https://skipodds.com/v1/fixtures?limit=3"
{
"fixtures": [{
"home_team": "France",
"away_team": "England",
"skipodds": {
"home": 0.501, "draw": 0.247, "away": 0.252,
"books_surveyed": 69,
"margin_removed": 0.05
}
}]
}
The responses never name a bookmaker — you get the cleaned consensus, so there's nothing gambling-adjacent to moderate if you're publishing to a general audience.
Bonus: your AI agent can use it too
The same API is exposed as a remote MCP server at https://skipodds.com/mcp (com.skipodds/skipodds in the official MCP registry). Point Claude, Cursor, or any MCP client at it and ask "what are the fair odds for the next big fight" — no key required for the demo quota.
Docs and the OpenAPI spec: skipodds.com/docs · openapi.json
Free tier is 100 requests/day with attribution. If you build something with it, I'd genuinely like to see it.
Top comments (0)