Skip to main content

How to price a CS2 skin by its float range

Price a CS2 skin by its exact float: how float-range buckets work per market, how to query them, and how to spot low-float premiums. Runnable API code.

Updated 6 min readIntermediatecurl · TypeScript · PythonMarkdown
On this page
  1. How float buckets work
  2. Step 1: fetch the float buckets for an item
  3. Step 2: find the bucket your float falls into
  4. Step 3: measure the low-float premium
  5. Step 4: watch one band over time
  6. Pitfalls that skew float prices
  7. When to reach for a different endpoint

Every CS2 skin has a float value between 0 and 1 that sets its wear. The market hash name only tells you the exterior band the float falls in, such as Field-Tested (0.15 to 0.38), but buyers care about where inside that band a skin sits. A 0.151 Field-Tested AK-47 | Redline looks close to Minimal Wear and usually sells above a 0.37 one, even though both share one market hash name and one headline price.

To price a specific item, you need prices by float range. SkinPricer collects them from the markets that segment by float and serves them from GET /v1/attribute-prices/latest as buckets: one price per float band, per market, with ask, bid, and listing counts. This guide covers how the buckets are built, how to find the one your float falls into, and how to measure the low-float premium.

How float buckets work#

Buckets follow each market's own segmentation rather than an invented common scheme, so bucket widths differ by venue. Every bucket describes its exact bounds in dimensions.float, as a half-open range (minInclusive: true, maxInclusive: false), and never crosses an exterior boundary.

MarketFloat bands
buff163BUFF's native, non-uniform ranges. For Field-Tested: 0.15 to 0.18, 0.18 to 0.21, 0.21 to 0.24, 0.24 to 0.27, and 0.27 to 0.38.
steamcommunity, marketcsgo, csfloat, dmarketUniform 0.01-wide bins: 0.15 to 0.16, 0.16 to 0.17, and so on, clamped to the exterior.

The full band table for every exterior lives on the attribute buckets concept page. The practical rule is simple: never parse or compare bucket labels across markets. Compare on dimensions.float.min and dimensions.float.max.

Step 1: fetch the float buckets for an item#

Scope the request to one item with marketHashName (or canonicalItemId). Float buckets are returned by default, from every supported market, and the latest read is included from the Developer plan up. Restrict venues with markets; any venue you ask for that has no bucket coverage is listed in sourceGaps instead of being silently dropped.

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

curl -s "https://pricing.skinpricer.com/v1/attribute-prices/latest?marketHashName=AK-47%20%7C%20Redline%20(Field-Tested)&markets=buff163,csfloat" \
  -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 res = await client.attributePrices.latest({
  marketHashName: "AK-47 | Redline (Field-Tested)",
  markets: ["buff163", "csfloat"],
});

for (const item of res.items) {
  console.log(`${item.market}: ${item.buckets.length} float buckets`);
}
import os

import requests

res = requests.get(
    "https://pricing.skinpricer.com/v1/attribute-prices/latest",
    params={
        "marketHashName": "AK-47 | Redline (Field-Tested)",
        "markets": "buff163,csfloat",
    },
    headers={"Authorization": f"ApiKey {os.environ['SKINPRICER_API_KEY']}"},
    timeout=10,
)
res.raise_for_status()
data = res.json()
print("markets without coverage:", data["sourceGaps"])
Response 200GET /v1/attribute-prices/latest
Field reference
{
  "bucketSchemaVersion": 1,
  "markets": ["buff163", "steamcommunity", "marketcsgo", "csfloat", "dmarket"],
  "currency": "USD",
  "asOf": "2026-06-23T09:18:45.864Z",
  "items": [
    {
      "canonicalItemId": "cmlofa7dh08ww01yo9lrpej3e",
      "marketHashName": "★ Karambit | Doppler (Factory New) - Phase 2",
      "market": "buff163",
      "buckets": [
        {
          "bucketId": "buff163:cmlofa7dh08ww01yo9lrpej3e:tag:446954:float:0-0.01",
          "bucketKey": "tag:446954:float:0-0.01",
          "bucketType": "attribute",
          "attributeType": "tag",
          "attributeTypes": ["tag", "float"],
          "dimensions": {
            "variant": "Phase2",
            "float": { "min": 0, "max": 0.01, "minInclusive": true, "maxInclusive": false },
            "fade": null,
            "pattern": null,
            "paintSeed": null
          },
          "sourceItemId": "44102",
          "sourceBucketId": "buff163:44102:tag446954:f0-0.01",
          "askCents": 197795,
          "avgAskCents": 201340,
          "medianAskCents": 199500,
          "bidCents": 179787,
          "askListingCount": 82,
          "bidOrderCount": null,
          "sourceUpdatedAt": "2026-06-23T09:10:00.000Z",
          "collectedAt": "2026-06-23T09:11:35.446Z"
        },
        {
          "bucketId": "buff163:cmlofa7dh08ww01yo9lrpej3e:tag:446954:float:0.01-0.02",
          "bucketKey": "tag:446954:float:0.01-0.02",
          "bucketType": "attribute",
          "attributeType": "tag",
          "attributeTypes": ["tag", "float"],
          "dimensions": {
            "variant": "Phase2",
            "float": { "min": 0.01, "max": 0.02, "minInclusive": true, "maxInclusive": false },
            "fade": null,
            "pattern": null,
            "paintSeed": null
          },
          "sourceItemId": "44102",
          "sourceBucketId": "buff163:44102:tag446954:f0.01-0.02",
          "askCents": 189676,
          "avgAskCents": 191220,
          "medianAskCents": 190100,
          "bidCents": 179344,
          "askListingCount": 66,
          "bidOrderCount": null,
          "sourceUpdatedAt": "2026-06-23T09:10:00.000Z",
          "collectedAt": "2026-06-23T09:11:35.446Z"
        }
      ]
    }
  ],
  "nextCursor": null,
  "sourceGaps": []
}
The documented response shape. Each bucket carries its own ask, bid, and listing counts, and dimensions.float holds the exact band.

Step 2: find the bucket your float falls into#

Given one skin's float, pick the bucket whose range contains it on each market. Respect the inclusivity flags so a float of exactly 0.18 lands in the 0.18 to 0.21 band, not the 0.15 to 0.18 one.

Node (SDK)
import type { AttributePriceBucket } from "@skinpricer/sdk";

/** The float bucket containing `value`, honoring half-open bounds. */
function bucketFor(value: number, buckets: AttributePriceBucket[]) {
  return buckets.find((b) => {
    const r = b.dimensions.float;
    if (!r) return false;
    const aboveMin = r.minInclusive ? value >= r.min : value > r.min;
    const belowMax = r.maxInclusive ? value <= r.max : value < r.max;
    return aboveMin && belowMax;
  });
}

const myFloat = 0.1512;
for (const item of res.items) {
  const bucket = bucketFor(myFloat, item.buckets);
  const ask = bucket?.askCents;
  console.log(item.market, ask == null ? "no listing in this band" : formatUsd(ask));
}

Step 3: measure the low-float premium#

The premium for a low float is easiest to read as a ratio: the ask in your band divided by the ask in the item's highest band on the same market. Comparing within one market avoids mixing different band widths and different fee structures. On BUFF, the 0.15 to 0.18 band of a Field-Tested item is the one closest to Minimal Wear, and it is typically where the premium concentrates.

Node (SDK)
for (const item of res.items) {
  const priced = item.buckets.filter((b) => b.askCents !== null && b.dimensions.float);
  const top = priced.reduce<AttributePriceBucket | undefined>(
    (hi, b) => (!hi || b.dimensions.float!.min > hi.dimensions.float!.min ? b : hi),
    undefined,
  );
  if (!top?.askCents) continue;

  for (const b of priced) {
    const ratio = b.askCents! / top.askCents;
    console.log(item.market, b.bucketKey, `${((ratio - 1) * 100).toFixed(1)}% vs highest band`);
  }
}
A premium measured on one or two listings is noise. Weight it by `askListingCount`, or skip bands below a minimum count.

Step 4: watch one band over time#

Each bucket has a stable bucketId. Pass one or more of them (bucketIds accepts a list) to attribute price history to get a points[] series with open, high, low, and close asks and the closing bid per interval. History reads require the Pro plan, default to the last 7 days, and accept 10m, 1h, or 1d spacing.

Node (SDK)
const lowBand = res.items
  .find((i) => i.market === "buff163")
  ?.buckets.find((b) => b.dimensions.float?.min === 0.15);

if (lowBand) {
  const history = await client.attributePrices.history({
    bucketIds: [lowBand.bucketId],
    granularity: "1d",
    from: new Date(Date.now() - 60 * 24 * 60 * 60 * 1000),
  });
  const points = history.items[0]?.buckets[0]?.points ?? [];
  console.log(points.map((p) => p.closeAskCents));
}
Response 200GET /v1/attribute-prices/history
Field reference
{
  "bucketSchemaVersion": 1,
  "markets": ["buff163", "steamcommunity", "marketcsgo", "csfloat", "dmarket"],
  "currency": "USD",
  "granularity": "10m",
  "items": [
    {
      "canonicalItemId": "cmlofa7dh08ww01yo9lrpej3e",
      "marketHashName": "★ Karambit | Doppler (Factory New) - Phase 2",
      "market": "buff163",
      "buckets": [
        {
          "bucketId": "buff163:cmlofa7dh08ww01yo9lrpej3e:tag:446954:float:0-0.01",
          "bucketKey": "tag:446954:float:0-0.01",
          "bucketType": "attribute",
          "attributeType": "tag",
          "attributeTypes": ["tag", "float"],
          "dimensions": {
            "variant": "Phase2",
            "float": { "min": 0, "max": 0.01, "minInclusive": true, "maxInclusive": false },
            "fade": null,
            "pattern": null,
            "paintSeed": null
          },
          "points": [
            {
              "bucketStart": "2026-06-16T14:40:00.000Z",
              "openAskCents": 192390,
              "highAskCents": 192390,
              "lowAskCents": 192390,
              "closeAskCents": 192390,
              "avgAskCents": 192390,
              "closeBidCents": 179367,
              "askListingCount": 87,
              "bidOrderCount": null,
              "firstObservedAt": "2026-06-16T14:41:02.190Z",
              "lastObservedAt": "2026-06-16T14:41:04.342Z"
            },
            {
              "bucketStart": "2026-06-16T14:50:00.000Z",
              "openAskCents": 192390,
              "highAskCents": 192390,
              "lowAskCents": 192390,
              "closeAskCents": 192390,
              "avgAskCents": 192390,
              "closeBidCents": 179367,
              "askListingCount": 87,
              "bidOrderCount": null,
              "firstObservedAt": "2026-06-16T14:51:03.475Z",
              "lastObservedAt": "2026-06-16T14:51:12.491Z"
            },
            {
              "bucketStart": "2026-06-16T15:00:00.000Z",
              "openAskCents": 192410,
              "highAskCents": 192410,
              "lowAskCents": 192410,
              "closeAskCents": 192410,
              "avgAskCents": 192410,
              "closeBidCents": 179385,
              "askListingCount": 87,
              "bidOrderCount": null,
              "firstObservedAt": "2026-06-16T15:00:49.830Z",
              "lastObservedAt": "2026-06-16T15:00:49.830Z"
            }
          ]
        }
      ]
    }
  ],
  "sourceGaps": []
}

Pitfalls that skew float prices#

  • Bands differ per market, so a BUFF 0.15 to 0.18 price and a Steam 0.15 to 0.16 price are not the same thing. Compare markets only on overlapping ranges.
  • Not every market reports buy orders per float band, so bidCents and bidOrderCount are often null outside BUFF. That means no band-level bid was observed, not a bid of zero.
  • A band's ask is the cheapest listing inside that band. On thin bands it can be a single listing, so check askListingCount before quoting it.
  • Without an item scope the endpoint returns a paginated snapshot of every item. Follow nextCursor until it is null (the SDK's latestEach does this for you).
  • Fade and pattern buckets are omitted by default. Add attributes=float,fade,tag for fade percentages (such as 90 to 93) and phase or pattern tags.

When to reach for a different endpoint#

For Doppler and Gamma Doppler, float bands sit inside each phase; the phase pricing guide covers that case. If BUFF is the only venue you need, the BUFF163 guide uses the market-scoped endpoints. And if you need each item's possible float range before you price anything, sync it from the item schema as shown in syncing the CS2 item catalog.

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.