How Sparkfare actually decides something is a deal

Most sites that call something a "deal" don't say what that actually means. Ours does, because the definition is simple enough to just write down — and simple enough to check against real numbers, which is the whole point.

The core rule

A route is flagged a deal when the cheapest fare in our latest search data falls at least 15% below that exact route's own trailing 30-day median price and at least two median absolute deviations below it. That's it. No external market benchmark, no machine-learning prediction, no comparison against any other route or any other traveler's price. The baseline is entirely this route's own accumulated history — nothing more exotic than that. The percentage on a deal badge, such as "25% below 30-day median, 31 observations," is how far that fare sits below that median.

The exact calculation

median = middle price, last 30 days
swing  = median of |price − median| (MAD)
deal   = today's fare ≤ median − 2 × swing
         AND today's fare ≤ 0.85 × median
  • The baseline is a median, not an average: the middle price of that route's cheapest daily fare over the preceding 30 calendar days, so one unusually cheap or expensive day can't skew it. It isn't weighted or decayed toward recent days.
  • The swing is the median absolute deviation (MAD): how far that route's daily prices typically sit from their median. A route that bounces around a lot needs a bigger drop to count as a deal; a steady route needs a smaller one.
  • Routes are keyed by origin and destination together. A JFK–Lisbon median and an ORD–Lisbon median are entirely separate baselines; we never pool prices across origins.
  • Today's own price never influences the median it's compared against. We classify against history as it stood before today, and only add today's price to the history file afterward — so the bar can't quietly get easier or harder to clear based on today's own number.

A route needs history before it can be judged

We require at least 10 distinct days of accumulated price history, spanning at least 14 days, before a route can be classified as a deal — or ruled out as "priced, not a deal." Below that, it shows as Building history, visibly dimmed on the board, rather than being scored against a statistically unreliable median. A missing day is simply skipped, never backfilled with a guessed price, since a synthetic number would quietly corrupt the median everything else depends on. And a price we retrieved more than 48 hours ago isn't judged at all. Fares are the lowest round-trip price found in search data we retrieved. They are not quotes, and the fare itself can be older than the retrieval time. The price on Aviasales can be higher or lower. The deal comparison uses our own 30-day history, not the Aviasales price.

The bar moves with how volatile a route actually is

Some routes swing in price far more than others on their own, with nothing unusual happening — a small dip on those routes isn't a meaningfully rare event, so we don't badge it as one. On top of a fixed 15% floor, the bar is set from each route's own price swings (the MAD above): the more a route normally bounces around, the further below its median a fare has to fall before we badge it.

One group of destinations, the featured ones, is the exception: those routes are always shown on their own merits, never judged against this bar and never badged as a deal. See how our destination groups work.

What this deliberately doesn't do

  • No external market-wide benchmark — the baseline is only ever this one route's own history.
  • No prediction of future prices.
  • No weighting toward recent days — every day in the 30-day window counts equally.
  • No cross-route or cross-origin comparison — a route is only ever compared against itself.

Commissions don't factor into any of this either. A route isn't shown as a deal because it pays us more, and a genuine deal isn't hidden because it pays us less — see our affiliate disclosure for the full picture on how we make money.

See today's board