Calculate Instagram posts engagement rate with Node.js + Instagram Web API

Parsa
9 min readApr 10, 2018

--

Deprecated: This API Disabled By Instagram (2018 April 12)

Learn to build a web app where users can type in a username and get Instagram posts engagement rate.

Pre-Project Setup

Node.js: Visit the official Node.js website to download and install Node.

Project Setup

Before we begin, all the code for this project can be found in the GitHub Repo

  1. Create an empty directory named “instagram-engagement-rate”.
  2. Open up your console, navigate to our new directory and run “npm init”
  3. Fill out the required information to initialize our project.
  4. Within our “instagram-engagement-rate” directory, create a file named “app.js” — this file will house the code for our application.

Now that we have all the puzzle pieces, we can start building!

Creating our Server (with Express JS)

First thing we need to do is get our server up and running. We’re going to use Express to accomplish this. Express is a minimalist web framework for Node.js — Express makes it very easy to create and run a web server with Node.

To use express, install it in the console:

npm install express --save

Once installed, we’re going to copy the boilerplate Express starter app from the Express documentation:

const express = require('express');
const app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});

Above is an example of the simplest application that we can create with Express. First we require the express package that was just installed. Then, we create an instance named app by invoking Express.

The `app.get(‘/’…` means we are specifically focusing on the root URL (/). If we visit the root URL, Express will respond with “Hello World!”.

The `app.listen(…` shows we are creating a server that is listening on port 3000 for connections.

We can test our server by running:

node app.js
// Example app listening on port 3000!

Now open your browser and visit: `localhost:3000` and you should see Hello World!

Setting up the index view

Instead of responding with text when someone visits our root route, we’d like to respond with an HTML file. For this, we’ll be using EJS (Embedded JavaScript). EJS is a templating language.

In order to use EJS in Express, we need to set up our template engine:

A template engine enables you to use static template files in your application. At runtime, the template engine replaces variables in a template file with actual values, and transforms the template into an HTML file sent to the client. This approach makes it easier to design an HTML page.
The short version is that EJS allows us to interact with variables and then dynamically create our HTML based on those variables! (This will make a lot more sense later in the tutorial)

First, we’ll install ejs in the terminal:

npm install ejs — save

We can then set up our template engine with this line of code (just below our require statements) in our app.js file:

app.set('view engine', 'ejs');

EJS is accessed by default in the “views” directory. So create a new folder named “views” in your directory. Within that “views” folder, add a file named “index.ejs”. Think of our “index.ejs” file as an HTML file for now.

Real quick, here’s what our file structure should look like thus far:

| — instagram-engagement-rate
| — views
| — index.ejs
| — package.json
| — app.js

Awesome, here’s a boilerplate for our index.ejs file. I’m not going to go over this file as this is not an HTML tutorial, but it should be pretty straight forward as we’re not using any EJS just yet. The html is just a form with one input for a Instagram username, and one submit button:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Instagram Engagement Rate</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script defer src="https://use.fontawesome.com/releases/v5.0.9/js/all.js"
integrity="sha384-8iPTk2s/jMVj81dnzb/iFR2sdA7u06vHJyyLlAd4snFpCl/SnyUjRrbdJsw1pGIl"
crossorigin="anonymous"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<div class="mt-3">
<h1>Instagram Engagement Rate</h1>
<form method="post" action="/" class="mt-5 col-sm-12 col-md-6 p-0">
<div class="form-group">
<label for="username">Instagram Username</label>
<input type="text" name="username" class="form-control" id="username" placeholder="Enter Username">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</body>
</html>

Once you have the above code copied into your index.ejs file, you’re almost done! The final thing we need to do is replace our app.get code:

app.get('/', function (req, res) {
// OLD CODE
res.send('Hello World!')
})

Above is the old code where we send the text ‘Hello World!’ to the client. Instead, we want to send our index.ejs file:

app.get('/', function (req, res) {
// NEW CODE
res.render('index');
})

Instead of using `res.send` , we use `res.render` when working with a templating language. `res.render` will render our view, then send the equivalent HTML to the client.

At this point, wee can test again by running:

node app.js
// Example app listening on port 3000!

Now open your browser and visit: `localhost:3000` and you should see our index.ejs file being displayed!

Adding a CSS File

Yours will look a little less ‘pretty’ than mine. That’s because I’m making use of a css file to style my HTML. Here’s how we get our CSS to work:

You’ll need to add a new folder to our project called “public”. Within that folder create a css folder, and finally create a file named “style.css”. Here’s your new file structure:

|-- instagram-engagement-rate
|-- views
|-- index.ejs
|-- public
|-- css
|-- style.css
|-- package.json
|-- app.js

Express wont allow access to this file by default, so we need to expose it with the following line of code:

app.use(express.static('public'));

This code allows us to access all of the static files within the ‘public’ folder.

Finally, we need our CSS. Since this isn’t a CSS course, I’m not going to be going over the specifics, but if you’d like to use my CSS, you can copy it from here.

Setting up our POST Route

By now, your app.js file should look like this:

const express = require('express');
const app = express();
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.get('/', function (req, res) {
res.render('index');
})

app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})

We have one get route, and then we create our server. However, for our application to work, we need a post route as well. If you look at our `index.ejs` file, you can see that our form is submitting a post request to the `/` route:

<form action="/" method="post">

Now that we know where our form is posting, we can set up the route! A post request looks just like a get request, with one minor change:

app.post('/', function (req, res) {
res.render('index');
})

But instead of just responding with the same html template, lets access the username the user typed in as well. For this we need to use an Express Middleware.

Express is a minimalist framework. However, we can make use of Middleware (functions that have access to the req and res bodies) in order to preform more advanced tasks.

We’re going to make use of the `body-parser` middleware. `body-parser` allows us to make use of the key-value pairs stored on the `req-body` object. In this case, we’ll be able to access the username the user typed in on the client side.

To use `body-parser` , we must install it first:

npm install body-parser --save

Once installed, we can require it, and then make use of our middleware with the following line of code in our app.js

const bodyParser = require('body-parser');
// ...
// ...
app.use(bodyParser.urlencoded({ extended: true }));

For the scope of this project, it’s not necessary you understand exactly how that line of code works. Just know that by using `body-parser` we can make use of the `req.body` object.

Finally, we can now update our post request to log the value of ‘username’ to the console.

app.post('/', function (req, res) {
res.render('index');
console.log(req.body.username);
})

Lets test it!

node app.js
// Example app listening on port 3000!

Now open your browser and visit: `localhost:3000` , type a city name into the field and hit enter!

If you go back to your command prompt, you should see the username displayed in the prompt! Awesome, you’ve now successfully passed data from the client to the server!

If you can’t get it to work, here’s what your app.js file should look like now:

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.get('/', function (req, res) {
res.render('index');
})
app.post('/', function (req, res) {
console.log(req.body.username);
res.render('index');
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})

Instagram Web API

Now we ready to request to Instagram for fetch posts data. For this we use Instagram Web API npm package, First install:

npm install instagram-web-api --save

For saving cookies to disk by using a `though-cookie` store.

npm install tough-cookie-filestore2 --save

Once installed, we can require it in our app.js

const Instagram = require('instagram-web-api')const FileCookieStore = require('tough-cookie-filestore2')
const { username, password } = process.env // Only required when no cookies are stored yet
const cookieStore = new FileCookieStore('./cookies.json')const client = new Instagram({ username, password, cookieStore })

Tested in post request route:

;(async () => {
await client.login();
const instagram = await client.getUserByUsername({username: req.body.username});
res.send(instagram);
})()

After restart server and submit a Instagram username you should see JSON response:

How do I calculate my engagement rate on Instagram, per post?

It’s much easier than it looks.
Say you have a following of 2,500, your ‘engagement’ is measured by your likes and comments combined per post, divided by your following.

Get a pen and paper handy and select a post to analyse.
Note down the number of comments and number of likes that post received.
Let’s say your total likes were 137 and comments came to 10.

137 + 10 = 147

You then need to take this magical number and divide it by your total followers, and times it by 100 (this will give you the percentage).

147 / 2,500 x 100 = 5.88%

Your total engagement rate for this post is 5.88% which is sitting smack bang in the middle of the average engagement rate on Instagram.
We suggest keeping a spreadsheet with your post types and engagement rates so you can accurately gauge what your audience are responding to, and what they’re not.

PLANN - How Do I Calculate My Engagement Rate on Instagram?

According to the engagement rate formula we need get comments and like count. In JSON response `edge_owner_to_timeline_media > edges` list of last user posts.

Complete post route code:

let request_username = request.body.username;
if (!request_username || request_username.length === 0)
response.redirect('/');
let images = [], output = [], like_c, comments_c, engagement_rate, engagement_rate_sum = 0,
engagement_rate_avg = 0,
followers = 0;
(async () => {
try {
await client.login();
const instagram = await client.getUserByUsername({username: request_username});
if (instagram['has_blocked_viewer'] === false && instagram['edge_owner_to_timeline_media']['count'] > 0) {
followers = instagram['edge_followed_by']['count'];
let edges = instagram['edge_owner_to_timeline_media']['edges'];
for (let p in edges) {
if (edges.hasOwnProperty(p)) {
like_c = edges[p]['node']['edge_liked_by']['count'];
comments_c = edges[p]['node']['edge_media_to_comment']['count'];
engagement_rate = ((like_c + comments_c) / followers) * 100;
engagement_rate_sum += engagement_rate;
engagement_rate = Number((engagement_rate).toFixed(3));
images.push({
"type": edges[p]['node']['__typename'],
"caption": edges[p]['node']['edge_media_to_caption']['edges'].length > 0 ? edges[p]['node']['edge_media_to_caption']['edges'][0]['node']['text'] : '',
"engagement_rate": engagement_rate,
"like": like_c,
"comments": comments_c,
"link": 'https://www.instagram.com/p/' + edges[p]['node']['shortcode'],
"thumbnail": edges[p]['node']['thumbnail_resources'][1]['src']
});
}
}
if (images.length > 0) {
engagement_rate_avg = engagement_rate_sum / images.length;
engagement_rate_avg = Number((engagement_rate_avg).toFixed(3));
}
}
output = {
'full_name': instagram['full_name'],
'username': instagram['username'],
'link': 'https://www.instagram.com/' + instagram['username'],
'biography': instagram['biography'],
'followers': followers,
'can_see': !((instagram['is_private'] && instagram['followed_by_viewer'] === false) || instagram['has_blocked_viewer']),
'engagement_rate_avg': engagement_rate_avg,
'images': images
};
response.render('index', {output: output});
} catch (err) {
console.log(err);
response.render('index', {error: true});
}
})();

And to display response in index.ejs:

<% if(typeof error !== 'undefined' && error){ %>
<div class="alert alert-danger mt-3" role="alert">
Error in fetch data from Instagram!
</div>
<% }else if(typeof output !== 'undefined'){ %>
<hr>
<div class="mt-3 mb-5 clearfix">
<h3><a href="<%= output.link %>" target="_blank"><%= output.full_name || output.username %></a></h3>
<h4><%= output.biography %></h4>
<h5>Followers: <%= output.followers %></h5>
<% if(!output.can_see){ %>
<p>This Account is Private or You are Blocked by Account.</p>
<% }else{ %>
<h5>Engagement Rate Average: <%= output.engagement_rate_avg %>%</h5>
<br>
<div class="row">
<% output.images.forEach(function(image) { %>
<div class="col-sm-3 mb-3">
<a href="<%= image.link %>" target="_blank" class="image">
<i class="fas fa-<%= image.type === 'GraphVideo' ? 'video' : 'image' %>"></i>
<img src="<%= image.thumbnail %>" alt="<%= image.caption %>" title="<%= image.caption %>"
class="img-fluid">
</a>
<div class="row meta">
<div class="col-4"><i class="fas fa-star"></i> <%= image.engagement_rate %>%</div>
<div class="col-4"><i class="fas fa-heart"></i> <%= image.like %></div>
<div class="col-4"><i class="fas fa-comment"></i> <%= image.comments %></div>
</div>
</div>
<% }); %>
</div>
<% } %>
</div>
<% } %>

Run your code

Reminder: all of the code for this project can be found in the GitHub Repo

node server.js// Example app listening on port 3000!

Now open your browser and visit: `localhost:3000`

I hope you enjoyed this article ❤

--

--