How to Build a Dart Package Analytics Tool with the pub.dev API: Beyond the 30-Day Window — Opportunihub
Course Remote

How to Build a Dart Package Analytics Tool with the pub.dev API: Beyond the 30-Day Window

Oluwaseyi Fatunmole · Remote

At a glance

Type
Course
Organisation
Oluwaseyi Fatunmole
Location
Remote
Work mode
Remote
Deadline
Rolling / not stated
Posted
24 Sep 2026

About this course

<p>When I published my package on pub.dev, the first few days were exciting as the number of downloads climbed. 201 downloads in a few days!</p> <p>Then something strange happened. The number dropped: 120, then 55. That's when I knew something wasn't right.</p> <p>I didn't break anything. Nothing changed in the package. People did not stop using it.</p> <p>The window moved.</p> <p>That was my introduction to one of the most misunderstood things about pub.dev: the 30-day rolling download figure it shows you is not a total. It is not a cumulative count. It is a window. And when the spike that got you those initial downloads falls outside that window, your number collapses, even though every single person who downloaded your package still has it installed.</p> <p>That realization sent me down a rabbit hole. If pub.dev is only showing me a 30-day window, is there a way to see the full picture? Is there an API that exposes more? What is pub.dev actually doing under the hood?</p> <p>This article is about what I found, and the tool I built out of it.</p> <h2 id="heading-table-of-contents">Table of Contents</h2> <ul> <li><p><a href="#heading-table-of-contents">Table of Contents</a></p> </li> <li><p><a href="#heading-the-problem-with-the-30-day-window">The Problem With the 30-Day Window</a></p> </li> <li><p><a href="#heading-how-pubdev-actually-calculates-downloads">How pub.dev Actually Calculates Downloads</a></p> </li> <li><p><a href="#heading-the-apis-behind-pubdev">The APIs Behind pub.dev</a></p> </li> <li><p><a href="#heading-the-metrics-endpoint-the-full-story">The Metrics Endpoint: The Full Story</a></p> </li> <li><p><a href="#heading-building-pubtrace">Building PubTrace</a></p> </li> <li><p><a href="#heading-how-pubtrace-computes-its-numbers">How PubTrace Computes Its Numbers</a></p> </li> <li><p><a href="#heading-how-this-helps-engineers">How This Helps Engineers</a></p> </li> <li><p><a href="#heading-a-note-on-the-unofficial-endpoint">A Note on the Unofficial Endpoint</a></p> </li> <li><p><a href="#heading-conclusion">Conclusion</a></p> </li> </ul> <h2 id="heading-the-problem-with-the-30-day-window">The Problem With the 30-Day Window</h2> <p>When you publish a package on pub.dev, the platform shows you a download count. If you look at any package page right now, you'll see a number labeled "downloads." Most developers assume this is the total number of times their package has been downloaded since it was published.</p> <p>It is not.</p> <p>pub.dev shows a 30-day rolling window. It counts how many times your package was downloaded in the last 30 days, and only the last 30 days. Everything before that is invisible.</p> <p>Here is what that means in practice. You launch a package. You share it on Twitter, on LinkedIn, in developer communities. You get a spike. 200 downloads in the first week. Then things settle - maybe 10 downloads a week later.</p> <p>At launch: 200 downloads are visible. After 5 weeks: 50 downloads are visible (only the last 30 days), and maybe 40 downloads after 10 weeks.</p> <p>The number dropped by 75%, but your package was not abandoned or broken. It was quietly being used by the 200 people who already installed it. The downloads kept coming in, just at a slower rate than the initial spike.</p> <p>The window moved and the spike fell out of it. But what was displayed on pub.dev made it look like your package was dying.</p> <p>For someone tracking their package's growth, that can be misleading.</p> <h2 id="heading-how-pubdev-actually-calculates-downloads">How pub.dev Actually Calculates Downloads</h2> <p>Before looking at the APIs, it is worth understanding how pub.dev counts downloads in the first place.</p> <p>pub.dev counts how many times a package archive has been downloaded from its servers. When you run <code>pub get</code> or <code>flutter pub get</code> in a project, the pub tool checks your local <code>PUB_CACHE</code> first. If the package is already cached, it uses the cached version and no download happens. A download is only counted when the package is not in your cache.</p> <p>This means the download count is not a measure of how many projects use your package. It is a measure of how many times developers had to fetch it fresh from the server. If 1000 developers use your package but they all already had it cached, the download count for that period is zero.</p> <p>pub.dev is transparent about this. From their <a href="https://pub.dev/help/scoring">official scoring documentation</a>: "The download count is not a direct measure of how many users a package has. A package can have high usage with relatively low download counts, because the pub client caches the downloads in the <code>PUB_CACHE</code>."</p> <p>So the number you see on pub.dev is already an undercount of actual usage. And on top of that, it is only showing you the last 30 days of that undercount.</p> <h2 id="heading-the-apis-behind-pubdev">The APIs Behind pub.dev</h2> <p>When I realized pub.dev was only showing me a window, the first thing I did was look for APIs that might expose more. pub.dev has an official API documentation page at <a href="https://pub.dev/help/api">pub.dev offical api documentation</a>. Let's walk through what is documented there.</p> <h3 id="heading-the-score-endpoint">The Score Endpoint</h3> <p><strong>GET</strong> <code>https://pub.dev/api/packages/{package}/score</code></p> <p>This is the official endpoint that powers the download number you see on pub.dev. You can call it yourself right now:</p> <pre><code class="language-plaintext">curl https://pub.dev/api/packages/dart_exceptor/score </code></pre> <p>The response looks like this:</p> <pre><code class="language-json">{ "grantedPoints": 150, "maxPoints": 160, "likeCount": 5, "downloadCount30Days": 174, "tags": [ "sdk:dart", "sdk:flutter", "platform:android", "platform:ios", "platform:linux", "platform:macos", "platform:web", "platform:windows" ] } </code></pre> <p><code>downloadCount30Days</code> is the number pub.dev shows on the package page. It is the 30-day rolling window. Nothing more, nothing less.</p> <p><code>likeCount</code> is how many developers have liked the package.</p> <p><code>grantedPoints</code> and <code>maxPoints</code> are the pub points score from the pana analyzer.</p> <p>This endpoint is officially supported and officially documented. It will not change without announcement.</p> <h3 id="heading-the-package-metadata-endpoint">The Package Metadata Endpoint</h3> <p><strong>GET</strong> <code>https://pub.dev/api/packages/{package}</code></p> <pre><code class="language-plaintext">curl https://pub.dev/api/packages/dart_exceptor </code></pre> <p>This endpoint is part of the Hosted Pub Repository Specification V2, which is what the <code>pub</code> command line tool itself uses to resolve and download packages. It returns full package metadata: every published version, the pubspec for each version, the publish timestamps, and the package's overall information.</p> <p>This is what PubTrace uses to determine when a package was first published. If a package was published six weeks ago, it only has six weeks of history, not 52. The article needs to be honest about that. PubTrace reads the first publish date from this endpoint and uses it to label charts accurately.</p> <p>The response is large. The important fields for PubTrace are:</p> <pre><code class="language-json">{ "name": "dart_exceptor", "latest": { "version": "1.1.2", "published": "2026-07-12T10:00:00.000Z" }, "versions": [ { "version": "1.0.0", "published": "2026-07-01T10:00:00.000Z" } ] } </code></pre> <h3 id="heading-the-publisher-endpoint">The Publisher Endpoint</h3> <p><strong>GET</strong> <code>https://pub.dev/api/packages/{package}/publisher</code></p> <pre><code class="language-plaintext">curl https://pub.dev/api/packages/dart_exceptor/publisher </code></pre> <p>Response:</p> <pre><code class="language-json">{ "publisherId": null } </code></pre> <p>Or for a verified publisher:</p> <pre><code class="language-json">{ "publisherId": "dart.dev" } </code></pre> <p>PubTrace uses this to show who built the package. If the package is under a verified publisher, that is displayed. If not, the uploader's identity is shown as unverified.</p> <p>This endpoint is officially documented and officially supported.</p> <h2 id="heading-the-metrics-endpoint-the-full-story">The Metrics Endpoint: The Full Story</h2> <p>Here is where things get interesting.</p> <p>While exploring pub.dev's public surface, I found an endpoint that is not in the official API documentation but is publicly accessible and used by pub.dev itself internally:</p> <p><strong>GET</strong> <code>https://pub.dev/api/packages/{package}/metrics</code></p> <pre><code class="language-plaintext">curl https://pub.dev/api/packages/dart_exceptor/metrics </code></pre> <p>pub.dev is explicit about this distinction. From their <a href="https://pub.dev/help/api">official api documentation</a>: "pub.dev may expose API endpoints that are available publicly, but unless they are documented here, we don't consider them as officially supported, and may change or remove them without notice."</p> <p>The metrics endpoint is one of these. It is public. Anyone can call it. But it is not officially supported, which means it could change. PubTrace uses it because it is the only source of the data that matters, and every number it produces from this endpoint is independently verifiable by anyone with a terminal.</p> <p>The response from this endpoint includes a <code>scorecard</code> object with <code>weeklyVersionDownloads</code>. This is what pub.dev's own weekly chart is powered by. It contains 52 entries, one for each week over the last year, newest first. Each entry breaks down downloads by version range: total downloads, major version range, minor version range, and patch version range.</p> <p>A simplified version of the relevant section looks like this:</p> <pre><code class="language-json">{ "scorecard": { "weeklyVersionDownloads": { "totalWeeklyDownloads": [45, 38, 62, 71, 28, 19, 33, ...], "majorRangeWeeklyDownloads": [...], "minorRangeWeeklyDownloads": [...], "patchRangeWeeklyDownloads": [...] } } } </code></pre> <p>The array has 52 entries. Index 0 is the most recent week. Index 51 is the oldest week in the dataset.</p> <p>pub.dev shows you the sum of roughly the last 4 entries in <code>totalWeeklyDownloads</code> (approximately 30 days). The full 52 entries are sitting right there in the API response. Unused. Invisible to anyone looking at the pub.dev UI.</p> <p>That is when I decided to build something.</p> <h2 id="heading-building-pubtrace">Building PubTrace</h2> <p>When I understood what the metrics endpoint exposed, the question was simple: why call these APIs manually every time I want to check a package's history, when I could build something the entire Dart and Flutter community could use?</p> <p>That is how PubTrace was born.</p> <p><a href="https://pubtrace.dev"><strong>PubTrace</strong></a> <strong>is a free tool that shows the full 52-week download history of any Dart or Flutter package on pub.dev.</strong> No account needed. No sign up. Just go to pubtrace.dev, type in any package name, and see the complete picture that pub.dev does not show you.</p> <h3 id="heading-what-pubtrace-does">What PubTrace Does</h3> <img src="https://cdn.hashnode.com/uploads/covers/692776609bbf6fdcde84192d/d7960309-60e9-47bb-9a63-e2f778364101.png" alt="pubtrace.dev showing the download count for one of the most popular flutter packages 'DIO'" style="display: block;" width="600" height="400" loading="lazy"> <p>PubTrace is a free, open tool available at <a href="https://pubtrace.dev">https://pubtrace.dev</a>. You type in any package name published on pub.dev and PubTrace shows you:</p> <p><strong>The cumulative download chart.</strong> A 52-week line chart showing total downloads growing over time. Not a 30-day window. Not a weekly bar chart. A running total that shows the true growth trajectory of any package.</p> <p><strong>The real numbers.</strong> Total downloads across the full history window, likes, pub points, and the publisher information , all pulled directly from pub.dev's own APIs at the moment you request the page.</p> <p><strong>How old the data is.</strong> PubTrace shows you when the data was last fetched. The cache is explicit. There is no pretense of real-time data. It is fresh within an hour.</p> <p><strong>The verify panel.</strong> Every page has a verify section showing the exact curl commands used to fetch the data. You can copy any command, run it in your terminal, and reproduce every number yourself. This is the most important feature on PubTrace. It means you never have to trust PubTrace. You can verify it yourself, right now.</p> <p>Here is what looking up dart_exceptor on PubTrace shows compared to pub.dev:</p> <p>pub.dev shows: 174 downloads (30-day window) PubTrace shows: 174 downloads cumulatively over 8 weeks, with a chart showing exactly when the downloads came in and how the number grew</p> <p>Both numbers are sourced from the same pub.dev data. PubTrace just shows the full picture.</p> <p>Any developer, any package, no account required. Go to <a href="https://pubtrace.dev">https://pubtrace.dev</a> and try it.</p> <h3 id="heading-the-architecture-decision-no-database">The Architecture Decision: No Database</h3> <p>The most important architectural decision in PubTrace was to not store any data.</p> <p>Every number you see on PubTrace is fetched live from pub.dev's APIs at the moment you request a package. There is no database of download history. There is no historical record. Every chart is computed fresh, on the server, from pub.dev's own data, right now.</p> <p>This was a deliberate choice for one reason: honesty.</p> <p>If PubTrace stored its own historical data, you would have to trust that PubTrace's data is correct. You would have to trust that I collected it accurately, that I did not have downtime during a collection window, that my storage was not corrupted. You would be trusting a middleman.</p> <p>With the no-database architecture, you never have to trust PubTrace. Every number PubTrace shows you can be reproduced with a curl command. PubTrace is a computation layer on top of pub.dev's own data, not a source of truth in its own right.</p> <h3 id="heading-the-1-hour-cache">The 1-Hour Cache</h3> <p>Fetching live from pub.dev on every request would be wasteful and disrespectful to pub.dev's servers. PubTrace caches responses for one hour. This means:</p> <p>If you look up <code>dart_exceptor</code> at 3pm, PubTrace fetches from pub.dev and caches the result. If someone else looks up <code>dart_exceptor</code> at 3:30pm, they get the cached result. At 4pm, the cache expires and the next request fetches fresh data.</p> <p>The cache is explicit and displayed to users. You can see when the data was last fetched. There is no pretense that the data is real-time. It is fresh within an hour.</p> <h3 id="heading-the-verify-panel">The Verify Panel</h3> <p>Every package page on PubTrace has a Verify panel. It shows the exact curl commands used to fetch the data for that package. Any developer can copy those commands, run them in their terminal, and reproduce every number PubTrace shows.</p> <p>This is not just a nice feature. It is the entire point. PubTrace's value is not that you trust it. It is that you do not have to.</p> <h2 id="heading-how-pubtrace-computes-its-numbers">How PubTrace Computes Its Numbers</h2> <p>Understanding the computation helps you trust the output.</p> <h3 id="heading-the-cumulative-chart">The Cumulative Chart</h3> <img src="https://cdn.hashnode.com/uploads/covers/692776609bbf6fdcde84192d/67fe11eb-6bb9-4119-83a6-431ff844d170.png" alt="67fe11eb-6bb9-4119-83a6-431ff844d170" style="display: block;" width="600" height="400" loading="lazy"> <p>PubTrace takes the 52 weekly download entries from the metrics endpoint and computes a running total. Week 52 is the starting point. Each subsequent week adds its downloads to the running total. The result is a cumulative growth chart that shows the true trajectory of a package's download history.</p> <p>This is fundamentally different from what pub.dev shows. pub.dev shows a bar chart of weekly downloads, which makes a consistent package with steady 30 downloads per week look flat. PubTrace shows a line chart of cumulative downloads, which shows that same package growing steadily, week after week.</p> <p>Both are showing the same data. The cumulative view shows the full story.</p> <h3 id="heading-the-young-package-rule">The Young Package Rule</h3> <p>If a package was published less than 52 weeks ago, PubTrace labels the chart with the actual number of weeks of data available. A package published 8 weeks ago will show 8 weeks of history, clearly labeled. PubTrace does not extrapolate or estimate missing weeks. It shows exactly what is in the data and nothing more.</p> <h3 id="heading-the-truncated-history-rule">The Truncated History Rule</h3> <p>The metrics endpoint stores 52 weeks of data. For packages that are more than a year old, the data before 52 weeks ago is simply not available from this endpoint. PubTrace is transparent about this. The chart shows 52 weeks. It does not claim to show lifetime downloads from day one for old packages.</p> <p>For packages younger than 52 weeks, the chart shows everything since launch, which is the complete history.</p> <h3 id="heading-the-sanity-check">The Sanity Check</h3> <p>Every computation PubTrace does can be verified against the raw API response. The cumulative total for a package is the sum of all 52 entries in <code>totalWeeklyDownloads</code>. You can run the curl command yourself, sum the array, and get the same number PubTrace shows. If they differ, something is wrong, and I'd like to know about it.</p> <h2 id="heading-how-this-helps-engineers">How This Helps Engineers</h2> <h3 id="heading-for-package-authors">For Package Authors</h3> <p>The most immediate value is understanding your own package's real growth. The number on pub.dev today is not your package's story. It is a snapshot of the last 30 days. PubTrace shows you the full 52-week trajectory so you can see whether your package is growing, stable, or declining, and make decisions based on real data.</p> <h3 id="heading-for-portfolio-and-evidence">For Portfolio and Evidence</h3> <p>A lot of engineers in the Dart and Flutter community are building portfolios and applying for senior roles that require demonstrating community contribution and technical impact. A download count of 55 on pub.dev is not compelling evidence. A cumulative chart showing 174 downloads growing steadily over 8 weeks, with a verifiable source, tells a very different story.</p> <p>PubTrace gives you the full picture and gives you the tools to prove it. The verify panel exists specifically so that the numbers are independently confirmable. There is no need to trust you. The data speaks for itself and it is verifiable from pub.dev's own APIs.</p> <h3 id="heading-for-the-community">For the Community</h3> <p>Any developer can look up any public package on pub.dev through PubTrace. You can compare packages side by side. You can see how a package grew over its first year. You can make more informed decisions about which packages to depend on, not just based on pub.dev's current 30-day window, but based on the full trajectory.</p> <h3 id="heading-for-dart-and-flutter-ecosystem-transparency">For Dart and Flutter Ecosystem Transparency</h3> <p>The Dart and Flutter ecosystem is growing. More packages are being published every week. But the tools for understanding that growth have been limited to pub.dev's 30-day window and its weekly bar chart. PubTrace adds a layer of historical visibility that was always in the data but never surfaced in the UI.</p> <p>Every calculation is derived from pub.dev's own public APIs. Nothing is invented. Nothing is estimated beyond what the API provides. The goal is honest, quality data that any engineer can verify.</p> <h2 id="heading-conclusion">Conclusion</h2> <p>pub.dev's 30-day rolling download figure tells you something. It does not tell you everything. For package authors trying to understand their growth and for the community trying to make informed decisions about dependencies, that window is not enough.</p> <p>The data for a fuller picture exists. pub.dev exposes weekly download history through its metrics endpoint. The official APIs expose metadata, publisher information, and scores. PubTrace combines all of these, computes a cumulative view, and presents it in a way that is honest, verifiable, and useful.</p> <p>No database. No estimates. No trust required. Every number traceable to a curl command against pub.dev's own APIs.</p> <p>If you publish packages on pub.dev, your numbers are probably better than pub.dev is making them look. Go see the real story.</p> <p>Visit <strong><a href="https://pubtrace.dev">https://pubtrace.dev</a></strong>. Type in your package name or any package you are curious about. Check the verify panel. Run the curl commands yourself. Share the link with your team.</p> <p>The data was always there. Now it is visible.</p>

How to apply

  1. 1 Read the full details above and confirm you meet the eligibility criteria.
  2. 2 Prepare your documents — an updated CV, and any cover letter, proposal or certificates required.
  3. 3 Click Apply on official site to complete your application on Oluwaseyi Fatunmole’s official page.
  4. 4 Submit as early as possible — many close once filled.
Apply on official site

Sourced from freecodecamp. Always verify details on the official website. Opportunihub never charges you to apply.

Frequently asked questions

How do I apply for How to Build a Dart Package Analytics Tool with the pub.dev API: Beyond the 30-Day Window?

Review the full details and eligibility on this page, prepare your documents, then use the “Apply on official site” button to complete your application on Oluwaseyi Fatunmole’s official page.

Is this opportunity remote or location-based?

This opportunity is remote-friendly and open to applicants who can work from anywhere.

Is How to Build a Dart Package Analytics Tool with the pub.dev API: Beyond the 30-Day Window free to apply for?

Opportunihub lists this Course for free. Legitimate Courses do not ask for payment to apply — never pay a fee to submit an application.