Skip to main content

Steam Market vs cash-market prices: how to compare them correctly

Steam Market prices are wallet credit, not cash. Learn how to compare Steam and cash-market CS2 prices after fees, using execution-adjusted quotes.

Updated 5 min readIntermediatecurl · TypeScript · PythonMarkdown
On this page
  1. Why a Steam price and a cash price are different numbers
  2. Step 1: pull both books side by side
  3. Step 2: compare what each side actually pays
  4. Rules of thumb for honest comparisons
  5. When to reach for a different endpoint

Put a Steam Community Market price next to a cash marketplace price for the same skin and the Steam number is usually higher, sometimes by a wide margin. That gap is not free money. The two prices are denominated in different things: Steam settles in Steam wallet balance, which can be spent on Steam but not withdrawn to a bank, while cash marketplaces pay sellers out in money. Comparing them as if they were the same currency is the most common mistake in CS2 price tooling, and it produces arbitrage signals that disappear the moment you try to trade them.

This guide shows how SkinPricer separates the two, how to pull both books side by side, and how to use the fee-aware executionAdjusted quote to compare what a trade actually pays on each side.

Why a Steam price and a cash price are different numbers#

Three things separate a Steam price from a cash price for the same item. First, the settlement asset: a Steam sale credits your wallet, and wallet balance cannot leave Steam. Second, fees: the seller of a Steam listing does not receive the listed price, and the execution model SkinPricer uses applies an estimated 15% seller fee to Steam bids. Third, liquidity: a Steam buy order may be real and deep, but filling it converts your skin into store credit, which is only worth its face value to someone who was going to spend it on Steam anyway.

SkinPricer encodes this in how it picks the best bid. Each venue's bid is classified as cash-executable (a seller can withdraw the proceeds) or not. In the default all-markets view, the cross-market bestBid on /v1/nbbo and /v1/pricing only considers cash-executable venues, such as BUFF163, CSFloat, Skinport, DMarket, Market.CSGO, and Waxpeer. Steam wallet-credit bids and trade-bot site balance stay in the per-market data, but they cannot win the cross-market bid unless you ask for them.

QuestionUse this
What is the best cash bid anywhere?Default GET /v1/nbbo (no markets list).
What is Steam's own ask and bid?GET /v1/pricing/:marketHashName and read the steamcommunity rows in markets[] and buyOrders[].
What would I really net selling on each side?GET /v1/nbbo with an explicit markets list, then read executionAdjusted.bestBid.price.

Step 1: pull both books side by side#

The pricing snapshot returns one representative ask per venue in markets[] and the standing bids in buyOrders[]. Restrict it to Steam plus the cash venues you care about, then compare Steam's ask with the cheapest cash ask. The ratio between them is the Steam premium for that item right now.

export SKINPRICER_API_KEY="sp_live_•••"   # from your account's API keys page

curl -s "https://pricing.skinpricer.com/v1/pricing/AK-47%20%7C%20Redline%20(Field-Tested)?markets=steamcommunity,csfloat,buff163,skinport" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"
// npm i @skinpricer/sdk
import { SkinpricerClient, formatUsd } from "@skinpricer/sdk";

const client = new SkinpricerClient({
  apiKey: process.env.SKINPRICER_API_KEY!,
  authScheme: "ApiKey",
});

const CASH_VENUES = ["csfloat", "buff163", "skinport"];

const item = await client.pricing.get("AK-47 | Redline (Field-Tested)", {
  markets: ["steamcommunity", ...CASH_VENUES],
});

const steam = item.markets.find((q) => q.market === "steamcommunity");
const cashAsks = item.markets.filter((q) => CASH_VENUES.includes(q.market));
const cheapestCash = cashAsks.reduce<(typeof cashAsks)[number] | undefined>(
  (best, q) => (best === undefined || q.price < best.price ? q : best),
  undefined,
);

if (steam && cheapestCash) {
  const premiumPct = (steam.price / cheapestCash.price - 1) * 100;
  console.log("Steam ask:", formatUsd(steam.price));
  console.log("Cheapest cash ask:", formatUsd(cheapestCash.price), "on", cheapestCash.market);
  console.log("Steam premium:", premiumPct.toFixed(1) + "%");
}
import os
from urllib.parse import quote

import requests

CASH_VENUES = {"csfloat", "buff163", "skinport"}
name = "AK-47 | Redline (Field-Tested)"

res = requests.get(
    f"https://pricing.skinpricer.com/v1/pricing/{quote(name, safe='')}",
    params={"markets": ",".join(["steamcommunity", *CASH_VENUES])},
    headers={"Authorization": f"ApiKey {os.environ['SKINPRICER_API_KEY']}"},
    timeout=10,
)
res.raise_for_status()
asks = {q["market"]: q["price"] for q in res.json()["markets"]}

steam = asks.get("steamcommunity")
cash = [p for m, p in asks.items() if m in CASH_VENUES]
if steam and cash:
    print(f"Steam premium: {(steam / min(cash) - 1) * 100:.1f}%")
A venue with no live listing for the item is absent from markets[], so always handle a missing Steam or cash quote.
Response 200GET /v1/pricing/:marketHashName
Field reference
{
  "canonicalItemId": "cmlofca920lka01yozajhixt3",
  "name": "Glock-18 | Water Elemental (Factory New)",
  "aggregate": {
    "minPrice": 6500,
    "maxPrice": 8012,
    "avgPrice": 7102,
    "medianPrice": 7119,
    "stdDev": 439.12,
    "marketCount": 10,
    "freshMarketCount": 9,
    "listingCount": 710,
    "updatedAt": "2026-06-23T21:59:48.717Z"
  },
  "markets": [
    {
      "market": "csfloat",
      "price": 6500,
      "currency": "USD",
      "fetchedAt": "2026-06-23T21:52:27.427Z",
      "ingestedAt": "2026-06-23T21:55:56.923Z",
      "quoteSize": 132,
      "ingestLatencyMs": 209496,
      "isStale": false,
      "sourceUpdatedAt": "2026-06-23T21:01:13.000Z",
      "sourceTimeKind": "last_modified",
      "sourceAgeSeconds": 3074
    }
  ],
  "buyOrders": [
    {
      "market": "buff163",
      "price": 6440,
      "currency": "USD",
      "fetchedAt": "2026-06-23T21:59:48.717Z",
      "ingestedAt": "2026-06-23T21:59:48.000Z",
      "quoteSize": 47,
      "totalQuantity": 47,
      "ingestLatencyMs": 0,
      "isStale": false
    }
  ],
  "bestAsk": {
    "market": "csfloat",
    "price": 6500,
    "updatedAt": "2026-06-23T21:52:27.427Z",
    "isStale": false
  },
  "bestBid": {
    "market": "buff163",
    "price": 6440,
    "updatedAt": "2026-06-23T21:59:48.717Z",
    "isStale": false
  },
  "spreadBps": 93,
  "marketCount": 10,
  "freshMarketCount": 9,
  "calculatedAt": "2026-06-23T22:07:13.752Z"
}
The documented pricing response. Each markets[] entry is one venue's representative ask in USD cents.

Step 2: compare what each side actually pays#

Sticker prices are only half the story. The executionAdjusted block on the NBBO response re-prices the best bid as what a seller would net after the venue's commission and any flat withdrawal fee, and re-ranks the best ask by executability. Call the NBBO twice: once in the default view, which gives the best cash bid, and once with an explicit list that includes Steam, which lets the Steam bid compete. Then compare the adjusted bids.

const name = "AK-47 | Redline (Field-Tested)";

const [cashView, withSteam] = await Promise.all([
  client.nbbo.get({ marketHashName: name }),
  client.nbbo.get({ marketHashName: name, markets: ["steamcommunity", ...CASH_VENUES] }),
]);

const cashBid = cashView.executionAdjusted?.bestBid;
const anyBid = withSteam.executionAdjusted?.bestBid;

if (cashBid) {
  console.log("Best cash bid nets", formatUsd(cashBid.price), "on", cashBid.market,
    "(gross", formatUsd(cashBid.rawPrice) + ")");
}
if (anyBid && anyBid.market === "steamcommunity") {
  console.log("Steam bid nets", formatUsd(anyBid.price), "in wallet credit, not cash");
}
# Default view: the best bid is cash-executable only.
curl -s "https://pricing.skinpricer.com/v1/nbbo?market_hash_name=AK-47%20%7C%20Redline%20(Field-Tested)" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"

# Explicit list: every listed venue's bid competes, Steam included.
curl -s "https://pricing.skinpricer.com/v1/nbbo?market_hash_name=AK-47%20%7C%20Redline%20(Field-Tested)&markets=steamcommunity,csfloat,buff163,skinport" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"
Live
Try it live

The default NBBO for AK-47 | Redline (Field-Tested), fetched live. Its bestBid is cash-executable.

Rules of thumb for honest comparisons#

  • Compare like with like: a Steam ask against a Steam bid, or a cash ask against a cash bid. Mixing them measures the wallet discount, not a spread.
  • Report the Steam premium as its own number. Traders find it useful, and it keeps wallet prices from leaking into cash valuations.
  • Use rawPrice for display and the adjusted price for decisions. The difference is the fee you are about to pay.
  • Check freshness on both sides. A Steam quote and a cash quote collected minutes apart can disagree simply because one moved first; isStale and updatedAt are on every best price.

When to reach for a different endpoint#

If Steam is the only market you need, the Steam prices guide covers current asks, bids, and sale history from the same API. To turn several signals into one number for a valuation, see how to estimate fair value. The underlying rules for cash-executable bids, spreads, and the execution-adjusted book are documented in Ask, bid & NBBO.

Endpoints used in this guide

Run this guide against live data

Plans start at $50/month on the Developer tier. Want to try first? Ask in our Discord for a free 2-day Developer key.