I’ve been using Medium for a while now, and while most of my experience has been good; lack of an API has given me a bit of uphill. The stats dashboard is easy to understand, but it’s not great for in-depth analytics. No API means no easy way of getting the stats out of Medium. Until now.

Getting The Stats

The thought occurred to me that the stats are shown in the graph, and could therefore be pulled from the DOM. I spent a few minutes putting together a bookmarklet and now I can get all the visible stats at the click of a button.

Bookmark this: Séance

(This link should contain the following JavaScript)

javascript:(function(){function d(a,b){var c=document.createElement("script");c.src="https://raw.github.com/eligrey/"+a+"/master/"+a;c.onload=b||function(){};document.body.appendChild(c)}function c(a){a=a.getAttribute("data-tooltip").split(/(?:view|read|rec)s? on/);return a[0]&&a[1]?a:!1}var e=[],f=document.querySelectorAll(".bargraph-bar");d("Blob.js");d("FileSaver.js",function(){for(var a=0;a<f.length;a++){var b=c(f[a]);e.push('"'+b[1].trim()+'", '+b[0].trim())}a="";b=document.querySelector(".graph-title-post"); a+=b.innerHTML;document.querySelector(".active > button > .total-views")&&(a+=" Views ");document.querySelector(".active > button > .total-reads")&&(a+=" Reads ");document.querySelector(".active > button > .total-votes")&&(a+=" Recommendations ");b=document.querySelector(".bargraph-bar:first-child");a+="("+c(b)[1].trim()+" to ";b=document.querySelector(".bargraph-bar:last-child");a+=c(b)[1].trim()+")";saveAs(new Blob([e.join("

")],{type:"text/plain;charset=utf-8"}),prompt("Save as:",a.trim())+".txt")})})();

When you add that link to your bookmarks bar, and click it on the Medium.com stats dashboard; you should be asked for the name of the file you would like to save the data to. It’ll save the data in a rough CSV format: October 13, 654. You can then parse/import/automate this data however you need to.

Making The Bookmarklet

The process of creating the bookmarklet was so straightforward that I thought it would be helpful to demonstrate it here; perhaps to inspire similar tools.

Step 1: Scaffolding

To begin making the bookmarklet; I created a skeleton page structure:

<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8" />

<title>Séance</title>

</head>

<body>

<a class="link" title="Save visible Medium.com stats">

Séance

</a>

<script type="text/javascript" class="handler">

(function(){ // ... your code here });

</script>

<script type="text/javascript">

(function(){ var link = document.querySelector(".link");

var handler = document.querySelector(".handler");

var script = handler.innerHTML.trim(); script = script.substr(0, script.length - 2);

script = "javascript:" + script + "());"; link.setAttribute("href", script); }());

</script>

</body>

</html>

Since bookmark lets are no more than links with JavaScript-based href attributes; this skeleton page provides a great platform on which to construct the script-string. Open this page up in your browser and click away at the link until it does exactly what you want.

Step 2: Scraping

Fast iteration is essential to efficient programming. I found the quickest way to iterate development of this particular bookmarklet was to copy the HTML that it scrapes into the skeleton page. That way I could target the elements and format their data as if I was doing so on the actual page, with the console.

Yum yum!

Use Chrome. Find the element you want to scrape and copy it’s HTML, through inspector. Paste that into your skeleton page and you can begin hacking away at it.

Step 3: Saving

This was the trickiest part for me. HTML5 (which is really just a buzzword to mean all of the neat new HTML/JavaScript/CSS3 things being produced presently) has come a long way, in terms of standardisation. One of the great new standards is the File API (needs link).

I read a few tutorials on how to use this; and came across a shim of the functionality (needs link) which lets you use these technologies in browsers that may not yet support them. I made the link add two scripts to the page so that I can use this shim to save the data to a txt file.

(function(){ function getElement(selector) {

return document.querySelector(selector);

} function getElements(selector) {

return document.querySelectorAll(selector);

} function getScript(name, callback) { var root = " https://raw.github.com/eligrey/ "; var script = document.createElement("script");

script.src = root + name + "/master/" + name;

script.onload = callback || function(){}; document.body.appendChild(script);

return script;



} function getData(element) { var tooltip = element.getAttribute("data-tooltip");

var data = tooltip.split(/(?:view|read|rec)s? on/); if (data[0] && data[1]) {

return data;

} return false; } var days = [];

var items = getElements(".bargraph-bar"); getScript("Blob.js");

getScript("FileSaver.js", function () { for (var i = 0; i < items.length; i++) { var data = getData(items[i]);

var count = data[1].trim();

var date = data[0].trim(); days.push("\"" + count + "\", " + date); } var options = {

"type" : "text/plain;charset=utf-8"

}; var title = ""; var name = getElement(".graph-title-post");

title += name.innerHTML; if (getElement(".active > button > .total-views")) {

title += " Views ";

} if (getElement(".active > button > .total-reads")) {

title += " Reads ";

} if (getElement(".active > button > .total-votes")) {

title += " Recommendations ";

} var first = getElement(".bargraph-bar:first-child");

title += "(" + getData(first)[1].trim() + " to "; var last = getElement(".bargraph-bar:last-child");

title += getData(last)[1].trim() + ")"; var blob = new Blob([days.join("

")], options);

saveAs(blob, prompt("Save as:", title.trim()) + ".txt"); }); });

The tooltip data (in the Medium graphs) contains things like 654 views on October 5. I get all the graph bars, split their tooltip data and add these to an array. The array is then joined on newlines and saved (using the shim library). There’s also a bit of logic to construct a sensible default file name based on visible and populated elements.

Conclusion

JavaScript is not only a great programming language, but also a great tool for doing these kinds of things to applications we use daily. We need to stop thinking of it as a way to build better tools and start thinking of it as a way to better use the tools others have already made for us!