FloatPilot logo

FloatPilot

GitHub X Login

Sandbox Config Documentation

What is a Config?

A config is a custom script written in JavaScript that analyzes a list of past skin sales (listings[]) and returns a single number — your suggested price or value estimation.

You also receive the current item object to compare against each listing.

Inputs

Return Value

Your script must return a single number — this will be shown as the estimated price on the CSFloat listing card. If your config can’t estimate (e.g. not enough data), return null.

Writing Your First Config

Here’s the simplest possible config — it returns the average price of all listings:

function run(listings, item) {
    let total = 0;
    for (let l of listings) {
      total += l.sale_price;
    }

 return total / listings.length;
}
        

But some configs will:

The following default config shows how to do all of the above.

Default Config Example

function run(listings, item) {
  function getFloatBucket(f) {
    const r = [[0.75,1],[0.5,0.75],[0.45,0.5],[0.4,0.45],[0.38,0.4],[0.3,0.38],[0.24,0.3],[0.21,0.24],[0.18,0.21],[0.165,0.18],[0.15,0.165],[0.12,0.15],[0.09,0.12],[0.07,0.09],[0.06,0.07],[0.01,0.06],[0.001,0.01],[0,0.001]];
    for (const [min, max] of r) if (f <= max && f > min) return [min, max];
    return null;
  }
  function within(a, b, t) {
    return typeof a === 'number' && typeof b === 'number' && Math.abs(a - b) <= t;
  }

  const b = getFloatBucket(item.float_value);
  if (!b) return null;

  const TOL_FADE = 3, TOL_BLUE = 3, now = Date.now(), decayDays = 1, trimPercent = 0.15;

  const baseOnly = listings.filter(s =>
    s.float_value > b[0] && s.float_value <= b[1] &&
    (item.fade_percent == null || within(s.fade_percent, item.fade_percent, TOL_FADE)) &&
    (item.playside_blue == null || within(s.playside_blue, item.playside_blue, TOL_BLUE)) &&
    s.stickers === '[]'
  );

  if (baseOnly.length < 3) return null;

  const sorted = baseOnly.slice().sort((a, b) => a.sale_price - b.sale_price);
  const cut = Math.floor(sorted.length * trimPercent);
  const trimmed = sorted.slice(cut, sorted.length - cut);

  const weighted = trimmed.map(s => {
    const age = (now - new Date(s.sale_date).getTime()) / (1000 * 60 * 60 * 24);
    const w = Math.exp(-age / decayDays);
    return { p: s.sale_price, w };
  });

  const sumW = weighted.reduce((a, x) => a + x.w, 0);
  const base = sumW ? weighted.reduce((a, x) => a + x.p * x.w, 0) / sumW : null;
  if (!base) return null;

  let stickerPrice = 0, boost = 0;
  try {
    const stickers = JSON.parse(item.stickers || '[]');
    stickerPrice = stickers.reduce((sum, s) => sum + (s.reference?.price || 0), 0);
    if (stickerPrice < 100) boost = 0.1;
    else if (stickerPrice < 1000) boost = 0.05;
    else boost = 0.02;
  } catch {}

  return Math.round(base + (stickerPrice * boost));
}
        

This config buckets float, filters by fade & blue %, removes outliers, weights recent sales, and boosts for stickers.

Security and Restrictions

Tips

This documentation is for FloatPilot config creators only.