BUFF sale history is now available - POST /v1/archive/buff returns sale prices and daily total supply since September 2024.

How to Get CS2 Sale Volume and Supply Data

Three cs2.sh endpoints report sale activity and they count different things. CSFloat reports actual daily sale counts from 2022, Steam reports its own purchase counts from 2013, and the aggregate archive reports an approximate estimate from 2023. None of them is total CS2 volume.

"How many of these sold?" has no single answer in CS2, because no marketplace publishes a global figure and each one counts only itself. The useful question is which covered market you mean.

Choose the volume definition first#

Need Endpoint Field Coverage
Cash marketplace sales, with variants POST /v1/archive/csfloat data[].volume From 2022
Steam Community Market purchases POST /v1/archive/steam data[].volume Daily from April 26, 2013
Approximate cross-source activity POST /v1/archive/history aggregate.hourly_volume From 2023

All three require a Scale or Enterprise API key and accept up to 100 items per request.

CSFloat and Steam volumes are marketplace-reported counts of real transactions. hourly_volume is explicitly an estimate: the hourly approximation in 1h responses, and the sum of those hourly estimates in each 1d bucket. Label it as approximate wherever it appears.

Youpin is the exception worth knowing. POST /v1/archive/youpin deliberately publishes no sale volume, because Youpin exposes one sale per sampling bucket. Counting the returned points measures how often a sample was published, not how many items traded. POST /v1/archive/buff behaves the same way: it returns sampled sale prices and the daily total_supply BUFF reports, and its count is the number of samples rather than a sale count.

Request activity and supply together#

bash
curl -X POST https://api.cs2.sh/v1/archive/history \
  -H "Authorization: Bearer <<YOUR_API_KEY>>" \
  -H "Accept-Encoding: gzip" --compressed \
  -H "Content-Type: application/json" \
  -d '{
  "items": ["USP-S | Printstream (Factory New)"],
  "start": "2023-01-01",
  "interval": "1d"
}'
json
"aggregate": {
  "time": "2026-04-27T23:59:07Z",
  "ask": 130.05,
  "ask_volume": 1225,
  "bid": 130.19,
  "bid_volume": 133,
  "hourly_volume": 27,
  "total_supply": 31291,
  "sample_count": 24
}
Field Type Description
hourly_volume integer Approximate sales in the bucket. Hourly for 1h, summed across the day for 1d.
total_supply integer Approximate cumulative copies of the item in circulation. aggregate only.
ask_volume / bid_volume integer Last-observed active listing and buy-order counts.
time string (date-time) When the last observation in the bucket happened.
sample_count integer Number of readings behind the bucket.

sources defaults to aggregate only, which is what you want here: hourly_volume and total_supply exist only on that source.

The four counts that are not sales#

This is where most CS2 volume analysis goes wrong. Four different fields look like quantity and only one of them counts transactions.

Field What it counts
ask_volume Active sell listings resting on the book right now
bid_volume Active buy orders resting on the book right now
depth levels in the Steam orderbook Quantity available at each price
total_supply Approximate copies of the item in existence

None of these is a sale. A falling ask_volume can mean listings sold, or were cancelled, or were repriced. Subtracting consecutive snapshots does not produce sale volume, and any model that does so will report phantom activity every time a seller changes their mind.

Reading the data correctly#

Use one definition per analysis. Adding Steam purchases to CSFloat sales gives a covered-market total, not all CS2 sales, and it silently weights the result toward whichever marketplace has better coverage for that item.

For cross-market comparison, report separate series or index each marketplace against its own baseline. Steam counts purchases settled in Steam Wallet funds; CSFloat counts cash transactions. They are not the same unit of activity.

Keep the matching price beside every volume value. A busy day at a falling price and a busy day at a rising price are different events, and volume alone cannot distinguish them.

A missing bucket is a gap, not a zero-sale period, unless the endpoint explicitly returns a zero. Forward-filling before summing inflates activity in exactly the quiet stretches where the error matters most.

Archive history updates about 1-2x per day, so hourly buckets describe the bucket width rather than the collection rate.

Reading supply correctly#

total_supply is approximate. Treat short-lived reversals or jumps as observations to validate rather than as literal destruction or issuance of items. Calculate change only between consecutive valid observations, and for issuance across a window, subtract the first valid observation from the last while disclosing any internal gaps.

A volume-to-supply ratio is a useful activity measure and a poor probability. It is not the chance that a listed item sells: the same ratio arises from heavy trading in a large population and from light trading in a tiny one. Store the raw sales and supply figures beside any ratio so those two cases stay distinguishable.

When items fail#

All three archive endpoints validate items independently and return 200 with both items and errors[]. not_in_archive is the one to expect: it means a valid item has no rows in that archive, which is a coverage fact rather than a retryable error. unknown_item and invalid_format cover naming problems.

A 404 not_found means no requested valid item has rows in that dataset at all. Request-level failures carry error, message, and a request_id.

Worked example: did activity follow a supply change#

Request 1d aggregate archive buckets across a window containing a case or collection change. Plot total_supply and hourly_volume on separate axes, never one unlabelled scale, and mark where supply moved.

Then check whether hourly_volume changed in the same direction and whether the aggregate ask moved with it. A supply increase that arrives with more sales and a flat price reads very differently from one that arrives with more sales and a falling price. Keep sample_count visible, because a bucket assembled from few readings can move for collection reasons rather than market ones.

Full references: POST /v1/archive/history, POST /v1/archive/csfloat, POST /v1/archive/steam. All need a Scale or Enterprise key.