Integrating Netlify Analytics and Eleventy

Before I start, know that I’m the usage of an undocumented a part of the Netlify API so that you must continue with warning. I’ve been looking forward to them to free up the medical doctors for someday now (even if it did not prevent me from development my very own demo) and I’m now not certain if it’s going to ever occur, however within the period in-between, I’ll proceed to play with it. Alright, so with that out of the best way, this weekend I labored on a groovy little factor I’ve added to my weblog. While you’ll see it at the proper hand aspect, it is this listing of hyperlinks right here:

List of Popular Posts

This listing used to be created by means of hitting the Netlify Analytics API for the website online, getting essentially the most seen content material up to now seven days, after which “manipulated” a little bit prior to rendering. Let me describe the stairs it took to get right here.

Getting the Analytics

Step one used to be to get the uncooked knowledge. First, I created a Personal Access Token. This is completed underneath your consumer profile at Netlify within the Applications phase:

Applications page

Once I had the important thing, I first wrote a script to get all of my websites. This used to be simply so I may get the ID of my weblog.

const fetch = require('node-fetch');
let token = 'my key brings all of the boys to the backyard'; (async () => { let end result = look ahead to fetch(`${token}`); let knowledge = look ahead to end result.json(); knowledge.type((a,b) => { if(a.identify < b.identify) go back -1; if(a.identify > b.identify) go back 1; go back 0; }); knowledge.forEach(d => { console.log(d.identify.padEnd(50, ' ') + d.site_id); }); })();

With the ID, I then used the undocumented API to get pages with essentially the most perspectives. I filter out to a date vary from now until seven days in the past. In case your curious, I came upon those API calls by means of the usage of my browser developer gear.

const fetch = require('node-fetch');
let token = 'rattling proper its higher than yours';
let siteId = 'the identity'; (async () => { let lately = new Date(); let lastWeek = new Date(); lastWeek.setDate(lately.getDate() - 7); let url = `https://analytics.products and${siteId}/pages?from=${lastWeek.getTime()}&to=${lately.getTime()}&timezone=-0500&restrict=10`; let end result = look ahead to fetch(url, { headers: { 'Authorization':`Bearer ${token}` } }); let dataOb = look ahead to end result.json(); console.log(dataOb.knowledge); })();

This is how the outcome seems to be:

[ { path: '/', count: 19221 }, { path: '/recentPosts/', count: 13885 }, { path: '/2020/05/01/handling-errors-in-vuejs', count: 683 }, { path: '/2020/05/15/lets-make-everyone-a-queen', count: 619 }, { path: '/2020/02/08/building-table-sorting-and-pagination-in-vuejs', count: 591 }, { path: '/2020/05/14/want-to-learn-vuejs', count: 570 }, { path: '/2020/08/08/drag-and-drop-file-upload-in-vuejs', count: 484 }, { path: '/2020/08/12/working-with-the-keyboard-in-your-vue-app', count: 386 }, { path: '/2020/09/01/using-geolocation-with-vuejs', count: 370 }, { path: '/2020/09/10/Adding-a-file-display-list-to-a-multifile-upload-HTML-control', count: 366 }

Right away you can understand the primary result’s for the house web page, one thing I’m going to forget about. The 2d end result, /currentPosts/, is a results of an optimization I did for the website online that I’ll give an explanation for in a little bit, as it comes into issue for this how I added this selection as neatly.

Alright, let’s get this into Eleventy!

Integrating with Eleventy

I started my integration with Eleventy by means of including a brand new world knowledge record named popularposts.js. This is – simply – one of my favourite options of Eleventy. By surroundings this up in my world knowledge record I’m ready to have it to be had for my pages later. Here is the code in the correct structure with Eleventy:

const fetch = require('node-fetch'); module.exports = serve as() { let token = procedure.env.NETLIFY_TOKEN; let siteId = procedure.env.NETLIFY_SITE_ID; go back new Promise(async (get to the bottom of, reject) => { let lately = new Date(); let lastWeek = new Date(); lastWeek.setDate(lately.getDate() - 7); let url = `https://analytics.products and${siteId}/pages?from=${lastWeek.getTime()}&to=${lately.getTime()}&timezone=-0500&restrict=15`; let end result = look ahead to fetch(url, { headers: { 'Authorization':`Bearer ${token}` } }); let dataOb = look ahead to end result.json(); let pages = dataOb.knowledge.filter out(d =>  d.trail === '/currentPosts/') go back false; go back true; ); get to the bottom of(pages); }); };

There’s a couple of issues other although. First, observe that the token and siteId are loaded by means of setting variables. I set those up in my website online settings and spotted that it did not paintings with netlify dev. This most often does paintings advantageous so I posted on their enhance boards to look what is up. In the period in-between I simply set the variables myself.

Next, understand I added a filter out to take away each / and /currentPosts/. I feel maximum other people will want the primary one, however now not the second one. It will have been higher to make use of an ordinary expression to just fit posts. Since my posts are all date based totally, I may have seemed for /2*** as an example.

That labored nice however then I spotted an issue. While the Netlify API returned the trail to the web page, it did not go back the name or date of the weblog submit. This is the place issues then were given a little bit difficult. At the time this information record runs, you wouldn’t have get admission to to assortment knowledge, the place my posts are living. That’s as a result of knowledge drives the pages so it has to load first.

In order to get this operating, I did the next. First, here is my format:

{% if popularposts %}
<phase elegance="widget widget-recent-posts">
<h2 elegance="widget-title">Popular Posts</h2>
<ul elegance="recent-posts"> {% for submit in popularposts restrict:5 %}  toTitle: collections.posts % {% if != "" %}
<li elegance="recent-item"><a href="{{ website online.url }}{{ submit.trail }}">{{ }}</a> <span> { date: "%B %e, %Y" }</span></li> {% endif %} {% endfor %}
{% endif %} 

I first see if I’ve popularposts (my knowledge name may fail), after which loop over every end result. For every, I exploit a filter out, toTitle, to “convert” the trail into web page knowledge that comes with my name and date. (So toTitle is not the most productive identify.) This filter out is outlined in .eleventy.js:

let titlePostCache = {};
eleventyConfig.addFilter('toTitle', (p, posts) => { if(titlePostCache[p]) go back titlePostCache[p]; for(let i=0;i<posts.period;i++) { if(posts[i].url == p) { titlePostCache[p] = { name: posts[i], date: posts[i].date}; go back titlePostCache[p]; } } // cache that we could not fit titlePostCache[p] = { name: ''}; go back titlePostCache;

For every trail, I loop over the posts assortment, search for a fit, and reutrn the name and date if that is so. Notice I exploit a cache for efficiency.

This labored neatly, but if I first of all installed my template, it required a rebuild of each and every unmarried web page within the website online when run. Because of that I hired the similar method I used for my remaining five posts content material. I put them each in one record template (/currentPosts/) that is loaded by means of a snappy jQuery name:


I do not even use JSON, I simply load the uncooked HTML proper into the DOM at the aspect there.

And that is it. Now, one factor you can almost certainly understand is that this information is most effective generated after I constructed the website online. I will be able to simply cope with that by means of scheduling a day-to-day construct. But as I weblog a few times per week very constantly and because this is not “industry the most important” knowledge, I’m advantageous with it updating on every occasion I submit a brand new weblog access (or make every other tweak, love to my talking web page. If you need to look extra of the code in the back of this, you’ll in finding it on the repo for this weblog:

p.s. I’m additionally making plans on taking a look at a Google Analytics model of this. They’ve were given an API so if I am getting time this week, I’ll submit a practice up!

Header photograph by means of Isaac Smith on Unsplash