Tracking GitHub downloads using Google Sheets

Posted on

If you use GitHub releases to host download packages, then you’re probably interested in how often these packages are being downloaded. You’d expect that the GitHub website provided that information under Insights > Traffic, but unfortunately, that’s not the case. Instead, you have to turn to the GitHub API.

To get information about download counts, you can query the Releases resource, which is part of the GitHub API. This resource returns a list of all your project’s releases, along with a list of assets for each release. For each asset, the JSON structure contains a download_count field that indicates the number of times this particular asset has been downloaded:

[
  {
    "url": "https://api.github.com/...",
    ...
    "tag_name": "1.2.0",
    ...
    "assets": [
      {
        "url": "https://api.github.com/...",
        "name": "MyRelease.msi",
        ...
        "download_count": 704,
        "created_at": "2021-04-09T10:03:15Z",
        "updated_at": "2021-04-09T10:14:24Z",
        "browser_download_url": "https://github.com/.../1.2.0/MyRelease.msi"
      }
    ]
  }
]

While the total number of downloads is interesting, the value doesn’t tell you anything about how download counts have evolved over time: Are download counts stagnating? Are they increasing? Are there any interesting patterns?

To answer these questions, you need to sample the GitHub API periodically (once a day, probably) and create a time series of download counts.

There are a million ways to write a script that requests the download count from Github once a day and records it as a time series somewhere – but there’s probably no easier way to do it than with Google Sheets and a few lines of AppScript:

function recordStats() {  
  var url = "https://api.github.com/repos/.../releases";


  var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
  var json = response.getContentText();
  var releases = JSON.parse(json);
  var msiDownloadsTotal = 0;

  var versionsSheet = SpreadsheetApp.getActive().getSheetByName("Versions");

  for (var i = 0; i < releases.length; i++)
  {
    for (var j = 0; j < releases[i].assets.length; j++)
    {
      if (releases[i].assets[j].browser_download_url.endsWith(".msi"))
      {
        msiDownloadsTotal += releases[i].assets[j].download_count;


        versionsSheet.appendRow([
          Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd"), 
          releases[i].tag_name, 
          releases[i].assets[j].download_count]);
      }
    }
  }

  var mainSheet = SpreadsheetApp.getActive().getSheetByName("Total");
  mainSheet.appendRow([Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd"), msiDownloadsTotal]);
}

What the script does is:

  1. Request the GitHub Releases resource
  2. Iterate over the releases and assets
  3. Append a line to the Versions sheet that indicates the total number of downloads per individual asset.
  4. Append a line to the Total sheet that indicates the total number of downloads across all assets.

To make sure the script runs once a day, all you have to do is set up a trigger that invokes the recordStats function once a day:

Trigger

In a truly serverless way, Google Sheets will now invoke the script once a day and every day, your sheet will grow:

Google sheet

Once you have a few weeks worth of data, you’re all set to set up graphs and run your analysis.

Any opinions expressed on this blog are Johannes' own. Refer to the respective vendor’s product documentation for authoritative information.
« Back to home