Tearline

Try it

Tearline

Playground

Docs

API

FAQ

Try it

Tearline

Playground

Docs

API

FAQ

Try it

Method

There is no Receiptify library.
There are three jobs.

what you are assembling

Nobody publishes a package that builds a Receiptify-style Spotify receipt, because a receipt generator is not one problem. It is three, and they are wildly unequal. Job one: get the listening history out of Spotify, which means OAuth, one endpoint, and a quota policy that decides whether the app can ever have users. Job two: draw a page that looks like till paper. Job three: turn that page into a PNG the user can post.

Jobs two and three are a weekend and are solved several different ways, compared further down. Job one is the entire difficulty of the project, and almost every tutorial on this topic ends before reaching it. Anyone deciding what to build should read the quota section first, because it determines whether the other two are worth starting.

where Tearline sits

Tearline is jobs two and three in one custom element, and has nothing to do with job one. That is worth saying plainly at the top rather than at the bottom: it removes the easy work, not the hard work. If the Spotify side does not clear, no rendering library rescues the project.

receipt.html

receipt.html
1
2
3
4
5
6
7
8
9
10
11
<script type="module" src="https://tearline.kynth.studio/tearline.js"></script>
<tear-line id="r" barcode="20260802">
<h1>Last 4 weeks</h1>
<hr>
// one <p> per item, artist + title + duration
</tear-line>
<script>
r.download('receipt.png'); // PNG, client-side
</script>

Jobs two and three, complete. The markup stays real text in the light DOM, so the track titles are still selectable and still read in order by a screen reader, and the PNG is produced in the browser with no server. The rest of the API is in the reference.

The cap

Five users.
That is the real limit.

Spotify quota modes · fetched 2 August 2026

development modeup to 5 usersWhere every newly-created app starts. Spotify's wording: "Up to 5 authenticated Spotify users can use an app that is in development mode." The app owner must hold a Spotify Premium account for the app to function at all.
extended quota modeunrestrictedRemoves the user cap and raises the rate limits. This is the mode every public Receiptify-style app needs, and it is granted by application rather than by request.
who may applyorganisations onlySince 15 May 2025: "Spotify only accepts applications from organizations (not individuals)."
eligibility bar250k MAUsThe stated criteria include an "Established Business Entity (legally registered business or organisation)", "Operating an active, and Launched Service", and "Maintaining a minimum of active users (at least 250k MAUs)".

what this means in practice

A Spotify app built by one person today can serve five authenticated users. Not five hundred in a trial tier, not five thousand pending review — five, and only while the owner holds a Premium subscription. Spotify's own wording is "Up to 5 authenticated Spotify users can use an app that is in development mode."

The escape hatch, extended quota mode, closed to individuals on 15 May 2025: "Spotify only accepts applications from organizations (not individuals)." The published criteria go further and ask for a registered business entity, a launched service, and "a minimum of active users (at least 250k MAUs)" — a bar that requires already having the audience the quota would let you serve.

So the honest read on this query in 2026 is that the popular Receiptify-style sites are grandfathered, operating under an organisation, or working from data the user supplies rather than from a live OAuth session. A new individual build is a five-seat toy unless it takes the third route, which the last section covers.

The call

One endpoint.
It shapes the whole UI.

GET /me/top/{type} · fetched 2 August 2026

GET /me/top/{type}artists | tracksThe single endpoint behind every listening-history receipt. One required OAuth scope: user-top-read.
time_rangedefault medium_termlong_term is "calculated from ~1 year of data and including all new data as it becomes available"; medium_term is "approximately last 6 months"; short_term is "approximately last 4 weeks".
limitdefault 20 · max 50The reason these apps offer a top 10 and a top 50 and nothing in between. Fifty is the ceiling on one call.
offsetdefault 0"The index of the first item to return." Paging past 50 is possible, but the receipt stops being readable long before the API stops answering.

top-tracks.js

top-tracks.js
1
2
3
4
5
6
7
8
9
10
11
// scope: user-top-read
const params = new URLSearchParams({
time_range: 'short_term', // ~4 weeks
limit: '50', // max is 50
});
const res = await fetch(
`https://api.spotify.com/v1/me/top/tracks?${params}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const { items } = await res.json();

Every listening-history receipt on the web offers the same three periods and the same two lengths, and it is not a shared design convention. It is the parameter list. Spotify defines exactly three time_range values — roughly four weeks, roughly six months, and about a year of data — and caps limit at 50, so "last month / last 6 months / all time" and "top 10 / top 50" are the API's shape showing through the UI.

One consequence worth designing around: long_term is not a lifetime history. Spotify describes it as calculated from about a year of data, so a receipt headed "all time" is overclaiming. Label it the way the source does.

The picture

Five ways to turn
the rows into a PNG.

approach · what you write · trade

canvas 2D, by handyou write everythingTotal control, and you re-implement text wrapping, ellipsis, tabular alignment and RTL yourself. Reasonable for a fixed 10-row layout; miserable the moment the design changes.
headless Chrome, server-sidea server per screenshotPixel-exact and it can load remote album art without a CORS argument. It also puts a browser in your deploy, a cold start in front of every share, and a bill on a free toy.
html-to-image / modern-screenshotyou write the CSSThe zero-dependency DOM-to-image route: serialise the node into an SVG foreignObject and paint it to a canvas. You still design the receipt from scratch. Compared on today's npm numbers at /dom-to-png.
html2canvasyou write the CSSRe-implements a renderer rather than using the browser's, so unsupported CSS silently comes out wrong. Its last release predates most of the CSS a modern receipt uses.
Tearlineyou write the rowsThe receipt look and the PNG export are both already written, as one custom element with no build step. It does nothing about the Spotify half, which is the half that is hard.

the failure everyone hits

Album art is the reason most first attempts export a receipt with holes in it. Four of the five approaches above rasterise in the browser, and the browser will not let a canvas holding cross-origin pixels give them back: drawing cross-origin data without CORS approval taints the canvas, after which toBlob() and toDataURL() throw instead of returning. Spotify's image CDN is a different origin, so covers pulled straight from the API trip it.

The fixes are to proxy the images through your own origin, to inline them as data: URIs before exporting, or to design a receipt that uses type instead of artwork — which is what actual till paper does. The mechanics, the second failure mode that looks identical but is not, and today's npm figures for the packages named above are all at export a DOM element as a PNG. The look itself — the monospace grid, the tabular figures, the torn edge — is given away in copyable CSS at receipt-style UI on the web.

Plan B

What one person
can still ship.

three routes that survive the cap

Build it for five people and stop pretending otherwise. A development-mode app is a perfectly good personal tool, and Spotify says as much — it describes the mode as suited to apps built for accessing data in a single account. Add the five allowed users by hand, ship it as a thing you and your friends use, and skip the landing page.

Or take the data from the user instead of from the API. A paste box, a CSV upload, or a file from a personal-data export removes OAuth entirely, which means no quota mode, no Premium requirement on the owner, no five-user ceiling, and no access token to store. The receipt is identical. This is the route that scales for an individual, and it is under-built relative to how many people want one.

Or make a receipt of something that is not Spotify. The format carries anything with rows, a total and a date: a month of expenses, a workout log, a reading list, a git history, an order confirmation. None of those have a gatekeeper, and the rendering and export work is the same work.

if you want the render half done

Tearline is the second and third jobs as one tag. Load one file, wrap your rows in <tear-line>, and it renders as the paper — torn edge, dashed rules, seeded barcode — and exports itself with download(). Zero dependencies, no build step, MIT. It makes no claim about the Spotify half and never will.

The playground on the home page edits a live receipt in the browser, and the documentation has every attribute and method. Everything on this page is also buildable from scratch, and both linked write-ups exist so that it can be.

Sources

Every claim here.
Fetched, not remembered.

checked 2 August 2026

developer.spotify.com — quota modesThe five-user development-mode cap, the Premium requirement, the 15 May 2025 organisations-only rule and the extended-quota eligibility criteria including 250k MAUs. Fetched twice on 2 August 2026.
developer.spotify.com — Get User's Top ItemsGET /me/top/{type}, the user-top-read scope, the three time_range values with their stated windows, and limit (default 20, maximum 50) and offset (default 0). Fetched 2 August 2026.
tearline.kynth.studio/tearline.jsThe component the render panel loads. 12,756 bytes, unminified, HTTP 200 on 2 August 2026.

what is deliberately not here

No ranking of the receipt-generator sites currently serving this query, and no claim about which of them is the original. Several are running on domains that did not exist when the genre started, their operators are not identifiable from the pages themselves, and a ranked list assembled from search results would be a guess wearing a table's clothes.

Quota policy is the fastest-decaying claim on this page — it changed for individuals in May 2025 and can change again. Both figures above carry the date they were read, and the Spotify documentation is the authority, not this page. The cross-origin canvas behaviour in the export section is browser security rather than policy and moves far more slowly; it is sourced to MDN on the export page.

Tearline

Wrap any HTML in one tag and it prints as a receipt.

Product

Overview

Features

Playground

FAQ

Docs

Install

API reference

Exporting a PNG

Accessibility

DOM to PNG, explained

Receipt-style UI

Spotify receipt generators

Code

Read the source

llms.txt

MIT licence

Studio

Kynth Studios

© 2026 Tearline. MIT licensed — free forever.

A Kynth Studios project

Tearline

Wrap any HTML in one tag and it prints as a receipt.

Product

Overview

Features

Playground

FAQ

Docs

Install

API reference

Exporting a PNG

Accessibility

DOM to PNG, explained

Receipt-style UI

Spotify receipt generators

Code

Read the source

llms.txt

MIT licence

Studio

Kynth Studios

© 2026 Tearline. MIT licensed — free forever.

A Kynth Studios project

Tearline

Wrap any HTML in one tag and it prints as a receipt.

Product

Overview

Features

Playground

FAQ

Docs

Install

API reference

Exporting a PNG

Accessibility

DOM to PNG, explained

Receipt-style UI

Spotify receipt generators

Code

Read the source

llms.txt

MIT licence

Studio

Kynth Studios

© 2026 Tearline. MIT licensed — free forever.

A Kynth Studios project