How to get CS2 skin price history at any interval
Fetch CS2 skin price history in 10-minute, hourly, or daily buckets, across all markets or split per market, ready for charts, alerts, and analysis.
On this page
A current price tells you where an item trades right now. A price history tells you whether that number is normal, how fast it moves, and how the spread between buyers and sellers behaves over time. You need one for every chart, every trend alert, and every model that asks whether a skin is cheap or expensive today.
SkinPricer stores time-bucketed history for every tracked item across every integrated marketplace and serves it from two endpoints: GET /v1/pricing/:marketHashName/history for one blended cross-market series, and GET /v1/pricing/:marketHashName/history/markets for one series per venue. This guide covers both, how bucket sizes are chosen, and the handful of fields that are easy to misread.
What a history bucket contains#
The response is a list of buckets, oldest first. Each bucket summarizes everything observed in one time window. Every price is an integer number of USD cents, so 3522 means $35.22.
| Field | Meaning |
|---|---|
timestamp | The start of the bucket, in UTC. The data describes the window that begins here. |
avgPrice / medianPrice | Mean and median of the prices observed in the window. |
minPrice / maxPrice | The cheapest and most expensive observation. The maximum can include extreme listings. |
bestAskCents / bestBidCents | The best ask and best bid in the window, null when a side had no quotes. |
spreadBps | The bucket's bid/ask spread in basis points, using the mid price as the denominator. |
listingCount | How many listings were observed in the window. |
totalQuantity / volume | Buy-order quantity (buy-order history only) and rolling sale count (sale history only). null otherwise. |
Step 1: request a series#
Put the item's exact market_hash_name in the path, URL-encoded, and send your API key. History reads require the Pro plan or higher, because they are served by the historical_data feature. With no query parameters you get the last 30 days of sell-side (ask) history at a bucket size chosen for you.
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)/history?interval=DAY_1&from=2026-06-27T00:00:00Z" \
-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 ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);
const series = await client.history.get("AK-47 | Redline (Field-Tested)", {
from: ninetyDaysAgo,
interval: "DAY_1",
});
for (const bucket of series.history) {
const ask = bucket.bestAskCents;
console.log(bucket.timestamp.slice(0, 10), ask === null ? "no asks" : formatUsd(ask));
}import os
from datetime import datetime, timedelta, timezone
from urllib.parse import quote
import requests
name = "AK-47 | Redline (Field-Tested)"
since = datetime.now(timezone.utc) - timedelta(days=90)
res = requests.get(
f"https://pricing.skinpricer.com/v1/pricing/{quote(name, safe='')}/history",
params={"interval": "DAY_1", "from": since.isoformat()},
headers={"Authorization": f"ApiKey {os.environ['SKINPRICER_API_KEY']}"},
timeout=10,
)
res.raise_for_status()
data = res.json()
print("bucket size served:", data.get("effectiveInterval"))
for bucket in data["history"]:
ask = bucket["bestAskCents"]
print(bucket["timestamp"][:10], "no asks" if ask is None else f"${ask / 100:.2f}"){
"canonicalItemId": "cmlofca920lka01yozajhixt3",
"name": "Glock-18 | Water Elemental (Factory New)",
"listingType": "SELL_OFFER",
"salesWindow": null,
"effectiveInterval": "1d",
"history": [
{
"timestamp": "2026-05-25T00:00:00.000Z",
"avgPrice": 4923,
"medianPrice": 4222,
"minPrice": 3522,
"maxPrice": 8805,
"listingCount": 1442,
"totalQuantity": null,
"volume": null,
"bestBidCents": null,
"bestAskCents": 3522,
"spreadBps": null
}
]
}Pull the last 30 days of AK-47 | Redline (Field-Tested) history right now, in your browser.
Step 2: choose the bucket size#
History is stored in three rollups: 10-minute, hourly, and daily. If you do not ask for a size, the API picks one from the length of your from to to window. If you pass interval, it is snapped to the nearest stored rollup, and the response echoes the size actually served in effectiveInterval.
| You ask for | You get |
|---|---|
No interval, window up to 7 days | 10-minute buckets |
No interval, window up to 180 days | Hourly buckets |
No interval, window longer than 180 days | Daily buckets |
MINUTE_5 or MINUTE_15 | 10-minute buckets |
HOUR_1 or HOUR_6 | Hourly buckets |
DAY_1 | Daily buckets |
Step 3: pick what you are charting#
The listingType parameter decides which side of the market the buckets describe. The default is the ask side, which is what most price charts show.
SELL_OFFER(default): listings for sale.bestAskCentsis the cheapest ask in the window, and the price statistics describe observed asks.BUY_ORDER: standing buy orders.totalQuantityreports how many units buyers were bidding for.SALE_HISTORY: completed sales as reported by the markets that publish them, paired withsalesWindow(24h,7d,30d, or90d, default30d).volumeis the number of sales in that trailing window.
Step 4: split the series per market#
The aggregate series answers "what did this item cost across the market". When you need to know where it was cheapest, or how one venue trades against another, call the per-market variant. It takes the same parameters plus an optional markets filter and returns a series array with one history per venue.
const byMarket = await client.history.byMarket("AK-47 | Redline (Field-Tested)", {
markets: ["buff163", "csfloat", "steamcommunity"],
interval: "HOUR_1",
});
for (const { market, history } of byMarket.series) {
const last = history.at(-1);
console.log(market, last?.bestAskCents ?? "no asks", "cents");
}{
"canonicalItemId": "cmlofczf90qj401vsd80dskd1",
"name": "AK-47 | Redline (Field-Tested)",
"listingType": "SELL_OFFER",
"salesWindow": null,
"effectiveInterval": "1d",
"series": [
{
"market": "buff163",
"history": [
{
"timestamp": "2026-09-22T00:00:00.000Z",
"avgPrice": 3343,
"medianPrice": 2942,
"minPrice": 2532,
"maxPrice": 5565,
"listingCount": 8472,
"totalQuantity": null,
"volume": null,
"bestBidCents": 2584,
"bestAskCents": 2532,
"spreadBps": -203
}
]
},
{
"market": "csfloat",
"history": [
{
"timestamp": "2026-09-22T00:00:00.000Z",
"avgPrice": 2524,
"medianPrice": 2526,
"minPrice": 2495,
"maxPrice": 2526,
"listingCount": 3655,
"totalQuantity": null,
"volume": null,
"bestBidCents": 2500,
"bestAskCents": 2495,
"spreadBps": -20
}
]
}
]
}Reading the numbers correctly#
nullmeans no data, not zero. A bucket with no bids hasbestBidCents: null; averaging it in as 0 drags every metric down.- In the aggregate series,
bestBidCentsis the best cash-executable bid that does not exceed the bucket's best ask, so the blended spread is never negative. Per-market series report each venue's own quotes, and their spreads can be negative. - History
spreadBpsdivides by the mid price. The live NBBO divides by the bid, so do not compare the two numbers directly. maxPriceon ask history includes whatever the most optimistic seller listed. It is not a fair-value estimate; chartbestAskCentsormedianPriceinstead.- Missing buckets mean nothing was observed in that window. Keep the gap in your chart rather than drawing a line straight through it.
When to reach for a different endpoint#
For the price right now, use the best bid and ask or the full live pricing snapshot. For float-range or Doppler-phase history, the item-level series is too coarse; read attribute price history instead, as shown in the float range guide. And if you are about to test a trading rule on this data, read the backtesting guide first: it covers point-in-time handling that a chart can safely ignore but a strategy cannot.
Endpoints used in this guide
Plans start at $50/month on the Developer tier. Want to try first? Ask in our Discord for a free 2-day Developer key.
Related guides
- History & backtestingAdvanced
How to backtest a CS2 skin trading strategy
Backtest a CS2 skin trading strategy on point-in-time bid and ask history, with fees, gaps, and no lookahead bias. Runnable data-pull code included.
GET /v1/pricing/:marketHashName/historyGET /v1/pricing/:marketHashName/history/markets5 min read - History & backtestingIntermediate
How to get BUFF163 prices, float buckets, and history in USD
Get BUFF163 prices, native float buckets, and price history for CS2 items in USD cents, without scraping or converting currency. Runnable API code included.
GET /v1/markets/buff163/latestGET /v1/markets/buff163/history6 min read - Prices & quotesBeginner
How to get Steam Community Market prices without scraping
Get Steam Community Market prices for CS2 without scraping or IP bans: current asks, per-market history, and a comparison with cash marketplaces.
GET /v1/pricing/:marketHashNameGET /v1/pricing/:marketHashName/history/markets5 min read - Prices & quotesIntermediate
How to estimate what a CS2 skin is really worth
Estimate what a CS2 skin is really worth: combine NBBO, recent history, and a suggested list price with confidence scores instead of one market's number.
GET /v1/recommendations/:marketHashNameGET /v1/nbbo6 min read