Quilore Request your data

How Quilore counts a skip, not the field Spotify gives you for it.

Your export contains a field called skipped. For seven and a half years of history it is wrong for everyone, and it looks like a fact about you rather than a defect in the file.

A skip and a short play sound like the same idea. They are two separate rules in this site's code, checked against different fields, and a track can be one without being the other. Getting that distinction wrong is how a statistics tool tells you something false and confident: that you barely ever skip anything.

Advertisements

The field that goes quiet for seven years

Every record in the extended streaming history carries a boolean called skipped. It would be reasonable to read that field and be done. We tried, against a real 160,634-record export, and found that skipped reads false for every single stream dated between 13 April 2015 and 16 October 2022, with a normal mix of true and false on either side of that window. Filtering on the field as documented reports a 0.00% skip rate for those seven and a half years. That does not read as a bug. It reads as a fact about a listener who apparently never once pressed forward, which is exactly the kind of wrong answer that never gets questioned.

What we derive instead

Every stream also carries reason_end, the platform's own account of why the track stopped. Four of its values describe a listener leaving before the track finished on its own terms, whatever the skipped flag claims:

reason_endWhat actually happened
fwdbtnSkipped forward, mid-track
backbtnSkipped back, mid-track
endplayPlayback stopped without finishing
unknownSpotify's own catch-all for an interrupted end

A record showing a genuine skip looks like this. Note the flag and the reason disagreeing with each other, which is the whole problem in one line:

{
  "ts": "2019-03-02T21:14:07Z",
  "ms_played": 41200,
  "master_metadata_track_name": "Overgrown",
  "master_metadata_album_artist_name": "James Vincent McMorrow",
  "reason_start": "trackdone",
  "reason_end": "fwdbtn",
  "skipped": false,
  "conn_country": "GB"
}

That is a listener holding the forward button forty-one seconds in, on a stream dated well inside the seven-and-a-half-year gap, with the field that is supposed to say so set to false. The rule this site applies is an OR across both signals, not a replacement of one by the other:

isSkipped = skipped === true || reason_end is one of the four above. Either signal is enough. Neither has to agree with the other.

Checking that the fix does not invent skips

Adding a second signal on top of a broken one is only safe if it never fires where the original field would have said no and been right. We checked, across the same 160,634 records: there is not one case of skipped === true paired with a reason_end outside that four-value set. The derived rule is a strict superset of the raw flag wherever the raw flag actually works. It adds coverage for the seven and a half years the flag is silent, and it does not disagree with the flag for a single stream in the years the flag is populated.

A skip and a short play are not the same rule

The site also has a separate threshold: a stream needs at least 30,000 milliseconds of ms_played to count as a play at all, which is Spotify's own definition of a stream and removes 9.1% of records in the same export, a meaningful share rather than a rounding error. It is tempting to fold that into "skip" too, since a track abandoned after four seconds is obviously a skip. It is also wrong, in both directions:

  • A twelve-second interlude that plays to reason_end: "trackdone" is short, but nobody skipped it. It is excluded from the play count and absent from the skip count, because it simply is not a skip.
  • Holding the forward button forty seconds into a six-minute track is a skip by every reasonable definition, and it clears the 30,000 ms threshold easily. It counts as a play and as a skip, at the same time.

Collapsing the two into one rule would either miss the second case or manufacture skips out of short intros and interludes that nobody actually abandoned. They stay two separate checks against two separate fields because that is what the export actually describes.

What this changes about your own numbers

If your listening history reaches back before October 2022, a skip rate computed the obvious way, by reading skipped directly, is not conservative. It is missing years. The gap is not evenly spread either: a heavy listener from 2016 will see their derived skip rate move far more than someone whose account started last year, because more of their history sits inside the window where the flag never worked.

About the data

The record counts, the date range and the field values above come from a single anonymised 160,634-record export, checked directly rather than estimated. Your own export will contain different numbers inside the same rule.

See your own skip rate.

Drop your Spotify export into Quilore. It runs in this tab and nothing leaves your device.

Get your export