There is a version of this feature that would have been easy to build and damaging to use.
That version would show your reading streak at the top of the library. It would send a push notification at 9pm if you had not read that day. It would show a sad broken-chain animation when you missed a day. It would email you a weekly digest with a subject line like “You only read 2 posts this week — here is how to do better.”
None of that is in Cozy Reader. But it was worth thinking carefully about why not, because the wrong kind of stats can turn something you do for pleasure into something you feel accountable for.
The Streak Problem
Streaks are a gamification mechanic borrowed from habit-tracking apps and language learning tools. They work by creating a loss-aversion effect: the longer your streak, the more anxious you become about breaking it. Duolingo has made this extremely effective. Millions of people open the app daily not because they want to learn a language but because they do not want to see their streak reset.
For language learning, that anxiety might be acceptable. The whole point is to build a habit. For reading, it is not. Reading is one of the few things left that people do slowly, for its own sake. An app that makes you feel guilty about not reading yesterday has misunderstood its own purpose.
Cozy Reader does have a longest streak stat. It lives at the bottom of a page that is itself one tap below the settings screen. There is no notification. There is no streak counter on the library screen. There is no broken-chain animation. It is just a quiet number: “Your longest reading streak was 8 days.” A fun fact, the way you might find a piece of trivia interesting without it changing anything about your day.
Stats as a Personal Record
The framing that guided this design was: these numbers are a record for the reader, not a performance metric for the app.
The difference sounds small but it shapes every decision. A performance metric is something the app uses to bring you back, to increase sessions per day, to optimise for engagement. A personal record is something you look at because you are curious about yourself.
Posts read this month. Total reading time. Average post length. First blog added. These numbers do not have targets attached to them. They do not compare you to other readers. They do not suggest you should be reading more. They simply describe what you have done, cleanly, without judgment.
This is roughly how a reading journal works. You might write down what you read and when. You might look back at the list occasionally. The journal does not tell you that you should have read more in February.
The stats are also deliberately hard to stumble across. They are not on the library screen, not on the home screen, not in the navigation bar. They sit behind a quiet row at the bottom of settings that shows just enough to intrigue — “47 posts read · since April 2026” — and rewards the tap with the full picture. Discoverable when you are curious. Invisible when you are not.
The Slow Calculation
There is one stat that took a little more thought to implement honestly: average reading time per post.
Most of the stats load immediately because they are simple database counts. Posts read is a COUNT query. Blogs followed is a COUNT query. These resolve in milliseconds and the numbers appear as soon as the page opens.
Average reading time is different. It requires loading the content of every post you have read, counting the words, dividing by average reading speed, and averaging across all entries. With a hundred read posts that is a meaningful amount of work for the device to do.
The solution was to make the work visible rather than hidden. When you open the stats page, most numbers appear immediately. The average reading time row shows a small spinner while it calculates. Once the result lands, a small refresh symbol appears next to it so you can recalculate after a reading session.
That honesty felt right for the app. It would have been possible to pre-cache the result and show it instantly, but that adds complexity for a number that most people will look at occasionally rather than daily. A visible spinner says: this is real data, calculated fresh, and it took a moment. That is fine.
What the Engagement Playbook Gets Wrong for Reading
There is a well-established playbook for how to use data to drive user engagement. Show progress. Set targets. Celebrate milestones with animations. Send reminders. Compare users to each other or to their past selves. Create loss aversion around streaks. This playbook works extremely well for fitness apps, savings apps, and productivity tools.
Applied to a reading app, it produces exactly the wrong outcomes. It produces streak anxiety. It produces the feeling that you have failed if you spent a quiet evening not reading. It turns a library into a scoreboard.
The goal of Cozy Reader is not to maximise the number of posts you read. It is to make the posts you do choose to read feel worth the time. An app optimised for that goal looks very different from one optimised for sessions per day.
Stats that serve the reader look like: a quiet record of what you have done, available when you are curious, invisible when you are not, carrying no targets and no judgment. That is a harder thing to build than a streak counter. But it is the right thing to build.
The reading experience is the product. The stats describe it. They do not try to change it.

Leave a comment