ReadingStatsResponse
Everything the reading dashboard shows, over one window.
devices object[]required
Friendly name where the client sent one, or the API key's label.
Ash's iPhoneduration objectrequired
Reading time split by how it was arrived at.
Deliberately two numbers rather than one. Time from the compatibility surfaces is reconstructed from the gaps between their writes: it undercounts and cannot see reading done from a downloaded book at all. Presenting a combined figure is fine; hiding that part of it is an estimate is not.
Milliseconds reconstructed server-side. An underestimate.
900000Milliseconds reported by a client that measured its own reading.
5400000Convenience sum of the two, so clients do not each reimplement it.
6300000formats object[]required
duration objectrequired
Reading time split by how it was arrived at.
Deliberately two numbers rather than one. Time from the compatibility surfaces is reconstructed from the gaps between their writes: it undercounts and cannot see reading done from a downloaded book at all. Presenting a combined figure is fine; hiding that part of it is an estimate is not.
Milliseconds reconstructed server-side. An underestimate.
900000Milliseconds reported by a client that measured its own reading.
5400000Convenience sum of the two, so clients do not each reimplement it.
6300000Null on the removed-from-library row.
cbzTrue on the single row that gathers reading whose book has since been deleted from the server, and whose format is therefore unknown.
The window actually used, after defaults were applied.
How finely to bucket the time series.
Possible values: [day, week, month]
periods object[]required
1ISO date of the bucket's start. Weeks start on Monday.
2026-06-01duration objectrequired
Reading time split by how it was arrived at.
Deliberately two numbers rather than one. Time from the compatibility surfaces is reconstructed from the gaps between their writes: it undercounts and cannot see reading done from a downloaded book at all. Presenting a combined figure is fine; hiding that part of it is an estimate is not.
Milliseconds reconstructed server-side. An underestimate.
900000Milliseconds reported by a client that measured its own reading.
5400000Convenience sum of the two, so clients do not each reimplement it.
63000001204series object[]required
Distinct books of the series read in the window.
Read-throughs finished in the window. Can exceed books only when a
book was genuinely re-read inside the window.
duration objectrequired
Reading time split by how it was arrived at.
Deliberately two numbers rather than one. Time from the compatibility surfaces is reconstructed from the gaps between their writes: it undercounts and cannot see reading done from a downloaded book at all. Presenting a combined figure is fine; hiding that part of it is an estimate is not.
Milliseconds reconstructed server-side. An underestimate.
900000Milliseconds reported by a client that measured its own reading.
5400000Convenience sum of the two, so clients do not each reimplement it.
6300000True on the single row that gathers reading whose book has since been
deleted from the server. That time still counts towards every total,
but which series it belonged to is no longer known. Its books and
booksFinished are always 0: both count distinct books, and deleted
books cannot be told apart.
Null on the removed-from-library row.
Null on the removed-from-library row.
Berserksummary objectrequired
Headline totals for the window.
12Books finished in the window, counted once per read-through: however many clients reported the same finish, it is one finish, and a genuine re-read counts again. Unlike time and pages, this is populated for reading that predates session tracking.
5duration objectrequired
Reading time split by how it was arrived at.
Deliberately two numbers rather than one. Time from the compatibility surfaces is reconstructed from the gaps between their writes: it undercounts and cannot see reading done from a downloaded book at all. Presenting a combined figure is fine; hiding that part of it is an estimate is not.
Milliseconds reconstructed server-side. An underestimate.
900000Milliseconds reported by a client that measured its own reading.
5400000Convenience sum of the two, so clients do not each reimplement it.
63000001240Distinct sittings, after adjacent writes were merged.
48Sittings whose client could report no time at all. A large number here explains a total that looks lower than the reading felt.
3Sittings whose client reported no page count. Only a reader that measures its own sitting reports one, so this covers reading that predates session tracking as well as apps that only save a position.
3{
"devices": [
{
"booksFinished": 0,
"deviceId": "string",
"deviceName": "Ash's iPhone",
"duration": {
"inferredMs": 900000,
"measuredMs": 5400000,
"totalMs": 6300000
},
"lastReadAt": "2024-07-29T15:51:28.071Z",
"pagesRead": 0,
"sessions": 0
}
],
"formats": [
{
"booksFinished": 0,
"duration": {
"inferredMs": 900000,
"measuredMs": 5400000,
"totalMs": 6300000
},
"format": "cbz",
"pagesRead": 0,
"removedFromLibrary": true,
"sessions": 0
}
],
"from": "2024-07-29T15:51:28.071Z",
"granularity": "day",
"periods": [
{
"booksFinished": 1,
"bucket": "2026-06-01",
"duration": {
"inferredMs": 900000,
"measuredMs": 5400000,
"totalMs": 6300000
},
"pagesRead": 120,
"sessions": 4
}
],
"series": [
{
"books": 0,
"booksFinished": 0,
"duration": {
"inferredMs": 900000,
"measuredMs": 5400000,
"totalMs": 6300000
},
"pagesRead": 0,
"removedFromLibrary": true,
"seriesId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"seriesName": "Berserk",
"sessions": 0
}
],
"summary": {
"books": 12,
"booksFinished": 5,
"duration": {
"inferredMs": 900000,
"measuredMs": 5400000,
"totalMs": 6300000
},
"pagesRead": 1240,
"sessions": 48,
"sessionsWithoutDuration": 3,
"sessionsWithoutPages": 3
},
"to": "2024-07-29T15:51:28.071Z"
}