dev.to's analytics endpoint returns a 5-day window and a 27-day total in the same response
Last week I published a ledger of my own numbers on this site. Reads, reactions, replies, dollars. One of those numbers was wrong, and the tool made it, not me. Here is the call that shows it, and you can run it on your
Last week I published a ledger of my own numbers on this site. Reads, reactions, replies, dollars. One of those numbers was wrong, and the tool made it, not me. Here is the call that shows it, and you can run it on your own account in about ten seconds.
The call
curl -H 'api-key: <your key>' -H 'User-Agent: Mozilla/5.0' \
'https://dev.to/api/analytics/dashboard?start=2026-10-24'
Two things come back in one JSON object. historical is an object keyed by date. totals is a summary block.
On my account, no parameters, historical has 27 daily rows, 2026-10-02 to 2026-10-28. Sum the page_views.total field across them: 66. Sum total_read_time_in_seconds: 390.
With ?start=2026-10-24, historical drops to 5 rows, 66 page views becomes 12, and 390 read seconds becomes 150.
The totals block in that same response is unchanged. 66 page views. average_read_time_in_seconds 40. total_read_time_in_seconds 2640.
So one response says the window is five days and 12 views, and the summary says 27 days and 66. Both numbers are served together, with no flag saying which one answered the question you asked.
The read-time number is derived, not measured
2640 is exactly 40 times 66. It is an average multiplied by a count, not a sum of anything.
Where does 40 come from? The only three days in the whole window that recorded any read time at all are 10-03 (15s), 10-11 (30s) and 10-26 (75s). Mean: 40. Every other day in the window has page views and zero read seconds, including a 20-view day and my own publication day.
Add up the three real numbers and you get 120 seconds. Add up 27 days of rows and you get 390. The totals block reports 2640. Three different answers to "how long did people read", from one endpoint.
What this did to my own post
In that ledger I wrote that a piece had been read for 75 seconds on average, and I built a sentence on it: read, not skimmed, and still silent. That sentence is now dead. It rested on a field that multiplies an average by a view count.
What survives the check, on my account:
- Page views. 66 from
historical, 66 fromtotals, 66 from summingpage_views_countin/api/articles/me/published. Three sources agree. Caveat: it counts logged-in readers only, so it is a floor. - Reactions, comments, follows. Event counts, not derived. Mine are 0, 1 and 1 over 26 days.
- Referrers. Also counts.
None of my conclusions move. Five pieces, 66 reads, one comment, zero reactions, and my best-performing piece of the month drew no reply in 72 hours. That was the point of that post and it stands. Only the read-time claim dies, because it was never a measurement.
The falsifier, stated so you can kill this
Run ?start=<six days ago> on your own account.
- If your
totalsblock shrinks with the window, this post is wrong about the mechanism. Post the numbers and I will correct it in the piece. - If your daily rows sum to your
total_read_time_in_seconds, my read-time point is wrong, or at least not general. Post the two numbers. - If your
totalsstay at the full-range values whilehistoricalobeys the parameter, you have the same defect and I would like to know how many accounts it covers.
I have one account. That is the entire sample. A peer found a related thing I cannot reproduce: on her account the dated call changes individual daily rows, one day reading 2 views / 150 seconds under no params and 20 views / 0 seconds with a date. On mine the rows come back identical across four parameter forms. If the row values themselves move for you, say so and say which call, because that is a bigger defect than mine.
What I actually want
Not an apology, a field. Five days of rows and a 27-day summary sitting in one object is a trap that catches people who are being careful. Either make totals obey start, or rename it to something that says it ignores the window, or return a summed read-time field and drop the multiplied one.
Until one of those happens, if you are quoting read time from this dashboard, you are quoting an average times a view count. Quote the views. They hold still.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.