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

How to Get Float Ranges for Every CS2 Item

Updated

Endpoints used: GET /v1/schema & GET /v1/market/buff/latest

Related pages: BUFF price API

cs2.sh's GET /v1/schema carries two different float bounds per item. float_range is the finish's native range across every wear it can exist in. wear_float_range clamps that to the exact wear row you are looking at. They answer different questions and mixing them produces wrong validation.

Float is what makes two copies of the same skin different products. Getting the bounds right is the foundation of any selector, filter, or pricing model that touches wear.

What cs2.sh provides for float data#

Property Value
Endpoint GET /v1/schema
Contents About 47,500 items and 110 collections, keyed by market_hash_name
Float fields float_range, wear_float_range, wears
Refresh Automatically when Counter-Strike 2 game files update
Access Available on all plans, including Demo and Developer
Priced float bands GET /v1/market/buff/latest, all plans

Read the two ranges#

json
"USP-S | Printstream (Factory New)": {
  "market_hash_name": "USP-S | Printstream (Factory New)",
  "wears": [
    "Factory New",
    "Minimal Wear",
    "Field-Tested",
    "Well-Worn",
    "Battle-Scarred"
  ],
  "float_range": { "min": 0, "max": 0.85 },
  "wear": "Factory New",
  "wear_float_range": { "min": 0, "max": 0.07 },
  "paint_index": 1142,
  "def_index": 61
}
Field Type Description
float_range object Float bounds for the finish across all its wears. Wear-carrying items only.
wear_float_range object Float bounds clamped to this exact wear row.
wears string[] Which exterior names the item exists in.
wear string The wear this schema row represents.

The example shows why the distinction matters. This Printstream finish spans 0 to 0.85 overall, but the Factory New row only spans 0 to 0.07. Validating a Factory New float against float_range would accept 0.40, which is not Factory New.

Use float_range to enumerate possible wears or validate a float against the finish. Use wear_float_range to build sliders, filters, or validation for one specific market item. The wears list tells you which exteriors exist, and the top-level key gives the exact market_hash_name for each selection.

Price an exact float#

Schema bounds describe what the game allows. They say nothing about price. For that, GET /v1/market/buff/latest splits each item into range buckets:

json
{
  "bucket_id": "float:0.15:0.18",
  "bucket_type": "float",
  "float": { "min": 0.15, "max": 0.18 },
  "ask": 218.55,
  "avg_ask": 231.47,
  "bid": 203.78,
  "ask_volume": 219,
  "bid_volume": 10
}

Find the bucket whose float.min is at or below your float and whose float.max is above it. Its ask is the cheapest listing you could actually buy at that float, which is usually well above the item's headline ask from prices/latest.

Bucket boundaries are half-open: min is inclusive and max is exclusive, so a float exactly on a boundary belongs to the range beginning at it. Use bucket_id to match the same range across requests and against POST /v1/market/buff/history, since decimal labels can be reformatted while the identity does not change.

Reading the data correctly#

BUFF range buckets are commercial segments, not physical definitions. They describe how BUFF groups its listings, which is narrower and more volatile than the item's real limits. Never replace schema bounds with observed bucket edges: a bucket can be absent even though the item physically supports that float, simply because nothing is listed there right now.

avg_ask beside ask tells you whether the cheapest listing in a band is representative. A wide gap inside one narrow band means the low listing is an outlier rather than the going rate for that float.

Items without wear do not carry these fields at all. Their absence is expected rather than missing data, and code should branch on presence rather than defaulting to a range.

Float is not the only attribute that moves price inside a wear. Paint seed and stickers are not in the price response, which is why two listings at the same float can sit far apart.

When fields are absent#

Items without wear carry no float_range, wear_float_range, or wears at all. Their absence is expected rather than missing data, so branch on presence rather than defaulting to a range.

For BUFF range buckets, an absent band means nothing is currently listed in that float range, not that the float is impossible. The schema remains the authority on what the item can physically be.

Worked example: validating a float and pricing it#

Given a float of 0.16 on a Printstream, first take the schema row for the wear you believe it is and check wear_float_range. A 0.16 float is not Factory New, whose row ends at 0.07; it falls in Minimal Wear. Resolve the correct market_hash_name from the wears list before doing anything else, because pricing the wrong wear row is a silent error.

Then request GET /v1/market/buff/latest for that item and walk buckets[] for the float bucket containing 0.16. Read its ask for the cheapest comparable listing and ask_volume to see how many exist. If no bucket covers 0.16, that is a listing gap rather than an impossible float, and the schema bounds remain the authority on what the item can be.

Full references: GET /v1/schema, GET /v1/market/buff/latest, BUFF range history.