You’ve learned a lot.
You should earn a lot.

Find a Job

Build a Chrome Extension for Real-time Price Tracking with Appbase

Realtime is easy using Appbase.io

We all dig e-commerce deals: whether’s it’s black friday, holiday special or just a good ol’ product discount offer.

In this tutorial, we will use some developer chops to take our love for e-commerce deals to the next level by building a price tracking chrome extension for flipkart.com, India’s largest e-commerce platform. We will break down the codebase and steps in a way that it’s easy for building a similar extension for another e-commerce site like eBay or Amazon.

Before diving into how to build this, let’s take a look at how it works.

Img: A gif showing our chrome extension in action.

The chrome extension lets you set a price alert when you are browsing product pages of flipkart.com for those specific products. For instance, set a 50% price off alert for the Faridaas tee that’s been on your wishlist since a while. Behind the scenes, the app track prices for the products and sends an e-mail when it matches the alert conditions.

For building this project, we use Javascript (with jQuery) and appbase.io — a hosted #datastreams API for creating realtime queries.

The only pre-requisite for following this tutorial is basic JavaScript chops. And we will cover everything else as we go along. Let’s get started!

We will break down the project into two components, and look at them one by one:

  1. Frontend Javascript and chrome-extension interface,
  2. Backend worker which uses Flipkart APIs and appbase.io for realtime price alerting.

The Chrome Extension

Let’s start with the interesting piece. We will be building a chrome extension. A chrome extension. is a static site — a combination of HTML, CSS and JavaScript that allows enhancing the user experience when browsing through Google Chrome.

Our goal with the chrome extension is to create a price alert UI based on e-commerce product page the user is browsing.

Step 1: Setup the project

The first thing we need to do is create the project and add all the files we need for the extension. Let’s start by creating a new directory that we’ll call price-monitoring-frontend. We’ll put all the files we need for the extension in this new folder. Chrome allows us to load up a plugin by pointing it at a folder that contains the extension files.

|_ _ _ _ js/
|        |_ _ _ _ background.js
|        |_ _ _ _ index.js
|_ _ _ _ index.html
|_ _ _ _ manifest.json
|_ _ _ _ icon.png

bower install bootstrap

All Chrome extensions require a manifest file. The Manifest file tells Chrome everything it needs to know to properly load up the extension in Chrome. So we’ll create a manifest.json file and put it into the folder we created. You can leave the manifest file blank for now.

touch manifest.json

Next we’ll need an icon for our extension. This needs to be a 128x128px PNG file and can be named as icon.png. Grab this one if you don’t have one handy.

touch icon.png

Next we’ll need an HTML page to show when a user clicks our Browser Action, so we’ll create index.html file.

touch index.html

Due to security policy of chrome extensions, it is recommended that we avoid any inline JavaScript into HTML files. It’s anyways a good practice to have Javascript and HTML separation. We will create an index.js inside the js directory and will later reference it in the index.html file.

mkdir -p js && touch js/index.js

Step 2: Create the manifest file

Now that we have a basic project structure in place, we need to add some code to our manifest file to describe our plugin to Chrome.

Usually a good first step in building the chrome extension is figuring out whether it makes more sense as a browser action or a page action. The main difference between the two is in how they appear in the browser’s UI:

  • Browser actions are permanently displayed to the right of the address bar. These are good if your extension can works on multiple websites (think adblock), or if the extension is website agnostic. This is probably the right option for most extensions.
  • Page actions are only displayed on certain pages, and their icon appears inside the address bar. This is the right options for extensions that only operate on a single website or specific websites (think Hacker News style enhancer). Page Actions explicitly tell the user which websites they need permissions for.

Our extension will be a page action, since it only works with one site, flipkart.com.

Open the manifest.json file and enter the following code:

  "manifest_version": 2,

  "name": "Flipkart price tracker",
  "description": "A flipkart.com extension to track product prices and set email alerts, built with appbase.io.",
  "version": "1.0",
  "background": {
    "scripts": ["js/background.js"],
    "persistent": false
  "page_action": {
    "default_icon": "icon.png",
    "default_popup": "index.html"
  "permissions": [

Most of the fields in this JSON file are self-explanatory, so I won’t waste your time explaining everything, but take note of the browser_action section where we specify what the default icon is and what HTML page should be displayed when the tab url contains flipkart.com.

You’ll also notice I’ve added a permissions section that specifies that we need to have permission to access the activeTab. This is required in order to enable us to get the URL of the current tab to pass on to Extension.

Step 3: Create the UI

The next step is to create the user interface that our Page Action will display when it is clicked.

Our user interface is going to be very simple that displays the detail about the product and allows to set the range and the email where you want to be notified.

Open up the index.html page and add the following:

<!doctype html>
 This page is shown when the extension button is clicked, because the
 "browser_action" field in manifest.json contains the "default_popup" key with
 value "popup.html".

  <title>Flipkart Price Tracker</title>
  body {
    font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
    font-size: 100%;
    min-width: 500px;

  .form-control {
    margin-bottom: 15px;

  .img-responsive {
    margin: 0 auto;
  <script src="bower_components/jquery/dist/jquery.min.js"></script>
  <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
  <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
  <script src="js/index.js"></script>
      - JavaScript and HTML must be in separate files: see our Content Security
      - Policy documentation[1] for details and explanation.
      - [1]: https://developer.chrome.com/extensions/contentSecurityPolicy

  <div class="container">
    <!-- Setting the header -->
    <div class="row">
        <h4>Product Price alert setter</h4>
    <!-- Form for setting the product price range for getting notification -->
    <div class="well">
      <select class="form-control inline" id="condition">
        <option value="lessThanValue">Less than a Value</option>
        <option value="lessThanCurrent">Less than Current Price</option>
        <option value="fixedPrice">At a fixed Price</option>
      <input id="greaterThanInput" style="display:none;"></input>
      <input class="form-control" id="lessThanInput" placeholder="Set Price"></input>
      <input class="form-control" id="email" placeholder="Enter your email"></input>
        <button class="btn btn-primary" id="submit" name="submit">Set Alert</button>
    <!-- Displaying the product information -->
        <td><img id="img" src="" height="200" width="150"></img>
        <td style="padding-left:50px;">
          <p><b>Product Name  : </b><span id="name"></span></p>
          <p><b>Current Price : </b><span id="current_price"></span></p>
    <div class="row">
      <img src="images/PoweredBy_Appbase.png" class=img-responsive center-block></img>


You’ll notice in this HTML I’ve included the index.js script. This is where we’ll put the logic for our extension that will execute when the extension is loaded and get notification button is clicked.

Step 4: Implement the logic

The last thing we need to do to create the plugin is to implement the logic that should execute when a user open the chrome extension icon and clicks the Get Notification button.

First we will edit background.js in js folder, and add the following code:

// listen for any changes to the URL of any tab.
chrome.tabs.onUpdated.addListener(function(id, info, tab) {
  if (tab.url.toLowerCase().indexOf("flipkart.com") > -1) {

We add the listener on tabs update to check the tab url if it contains the flipkart.com. On success, we display the page action.

Now, we will be working on index.js file. We’ll want to add an event listener to listen for the document to be loaded. When user selects the condition for the price range, it updates the variable which we then send it to the server.

When document is ready, we will get the current tab URL by calling getCurrentTabURL(). We check if there is product ID in the url, then we get the product details ( Name, current price ) of the given Product ID and display it in our extension

When the submit button is clicked, we’ll need to fetch the email and price range at which user wants to be notified. We send the parameters to our server which takes care of notifying when it is matched.

const serverAddress = ""
var productDetail;
document.addEventListener('DOMContentLoaded', function() {

  // When price condition is changed
  $('select#condition').on('change', function() {
    // If the user has selected "Less than current price"
    // We assign greaterThanInput value to  0
    // and set the lessThanInput value to current price of the product
    if ($('#condition').val() == "lessThanCurrent") {
      $('#greaterThanInput').attr('readonly', 'true');
    // If the user has selected "Fixed price"
    // We assign greaterThanInput value to be price entered by user
    // and set the lessThanInput value to be price entered by user
    else if ($('#condition').val() == "fixedPrice") {
    // If the user has selected "Less than a value"
    // We assign greaterThanInput value to 0
    // and set the lessThanInput value to be price entered by user
    else {

  // On clicking the set alert button, we make a call to our server
  // Sever indexes the product and set a trigger to send mail when condition is met
  $('#submit').on('click', function() {
    var parameters = {
      'lte': $('#lessThanInput').val(),
      'gte': $('#greaterThanInput').val(),
      'email': $('#email').val(),
      'productId': productDetail.productId
      type: 'GET',
      url: serverAddress + '/alert',
      data: parameters,
      success: function(d) {
      error: function() {
    alert("You will receive an email, whenever the product price reaches according to you condition.");

  $(document).ready(function() {
    // Get the current tab URL and fetch the product ID
    getCurrentTabUrl(function(url) {
      if ($.urlParam('pid', url) != null) {
        // Fetch the product details from the product ID
        getProductDetails({ 'productId': $.urlParam('pid', url) }, function(data) {
          //  Display the product details in the extension
          productDetail = data;
          var imageURL;
          for (var key in productDetail.imageurls) {
            imageURL = productDetail.imageurls[key];
          $('#img').attr('src', imageURL);


We define getCurrentTabUrl() to get the URL of the active tab.

function getCurrentTabUrl(callback) {
  // Query filter to be passed to chrome.tabs.query - see
  // https://developer.chrome.com/extensions/tabs#method-query
  var queryInfo = {
    active: true,
    currentWindow: true

  chrome.tabs.query(queryInfo, function(tabs) {
    // chrome.tabs.query invokes the callback with a list of tabs that match the
    // query. When the popup is opened, there is certainly a window and at least
    // one tab, so we can safely assume that |tabs| is a non-empty array.
    // A window can only have one active tab at a time, so the array consists of
    // exactly one tab.
    var tab = tabs[0];

    // A tab is a plain object that provides information about the tab.
    // See https://developer.chrome.com/extensions/tabs#type-Tab
    var url = tab.url;

    // tab.url is only available if the "activeTab" permission is declared.
    // If you want to see the URL of other tabs (e.g. after removing active:true
    // from |queryInfo|), then the "tabs" permission is required to see their
    // "url" properties.
    console.assert(typeof url == 'string', 'tab.url should be a string');



We then parse the product ID(pid parameter) from the URL fetched.

$.urlParam = function(name,url){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(url);
    if (results==null){
       return null;
       return results[1] || 0;

getProductDetails() takes Product ID as parameter and fetches the product details like name and current price from the Flipkart server by making Ajax request.

function getProductDetails(parameters, callback) {
    type: 'get',
    url: serverAddress + '/product',
    data: parameters,
    success: function(d) {
    error: function() {

Building backend components

We have frontend of chrome extension in place, where user can interact and set a price to be notified. Now, we will work on the server side aspect which tracks the price changes on Flipkart and notify user when the given condition is met. Img: Architecture diagram showing how the system works

Step 1: Setup Credentials

The first thing we need to do is create the project and all the files we need. Let’s start by creating a new directory that we’ll call “price-monitoring-backend”. We’ll put all the files that we will need to run on server side in this new folder.

|_ _ _ _ helper.js
|_ _ _ _ polling.js
|_ _ _ _ index.js
|_ _ _ _ appbase_credentials.json
|_ _ _ _ flipkart_credentials.json
|_ _ _ _ package.json

The above shows how our final directory structure would look. Let’s initialize all these files for later ease of access.

touch helper.js
touch polling.js
touch index.js
touch appbase_credentials.json
touch flipkart_credentials.json
touch package.json

In Node, the package.json file holds the configuration for our app. Node’s package manager (npm) will use this to install any dependencies or modules that we are going to use. We will update package.json with the following json:

  "name": "flipkart_extension",
  "version": "1.0.0",
  "description": "This is flipkart price alerting extension's backend worker",
  "main": "index.js",
  "scripts": {
    "test": "run"
  "repository": {
    "type": "git",
    "url": "https://github.com/appbaseio-apps/price-monitoring-flipkart-backend.git"
  "homepage": "https://github.com/appbaseio-apps/price-monitoring-flipkart-frontend",
  "dependencies": {
    "appbase-js": "^0.10.7",
    "express": "^4.13.3",
    "fs": "0.0.2",
    "request": "^2.65.0"

and then we will install the dependencies by running the following command inside the folder:

npm install

Next, we will create an app on Appbase and add the app credentials to appbase_credentials.json.

 "url": "https://scalr.api.appbase.io",
 "appname": "your_app_name",
 "username": "app_username",
 "password": "app_password",
 "type": "index_type"

We will update the Flipkart API credentials in flipkart_credentials.json

  "Content-Type": "application/x-www-form-urlencoded",

If you don’t have flipkart API credential, create an account at Flipkart Affiliate program and get the credentials from their dashboard. 

Step 2: Get the Flipkart product details

We will have to expose the REST APIs that our frontend will interact to set price alert and get product details.

First of all, let the add following code in index.js which will require the necessary packages. You will need to get the sendgrid api key from here and add it below.

  Requiring necessary helpers.
var express = require('express');
var request = require('request');
var fs = require('fs');
var app = express();
var Appbase = require('appbase-js');
var helper = require("./helper.js");

  Including appbase credentials stored in json file.
var appbaseCredentials = require('./appbase_credentials.json');
var sendgrid_api_key = "ENTER_YOUR_SENDGRID_API_KEY_HERE"

  Appbase Credentials. Just make new account at appbase and configure it according to your account.
  Creating object of appbase, passing appbaseCredentials.
var appbase = new Appbase(appbaseCredentials);

/* This is to access any file withn folder, no routing required for these files. */
app.use('/', express.static(__dirname + '/'));

index.js typically handles your app startup, routing and other functions of your application and does require other modules to add functionality. If you’re running a website or web app it would also handle become a basic HTTP web server replacing the role of something more traditional like Apache.

Let us write the helper function to get the product details using the Flipkart API and we will expose it globally so that any files can use it. Add the following code in your helper.js file:

    This is function which just gives details about products and call callback along with the details.
module.exports.getProductDetails = function(productId, callback) {
  var request = require('request');
  var options = {
    uri: 'https://affiliate-api.flipkart.net/affiliate/1.0/product.json?id=' + productId,
    method: 'GET',
    headers: require('./flipkart_credentials.json')
  var data;
  request(options, function(error, response, body) {
    if (!error && response != undefined && response.statusCode == 200) {
      data = JSON.parse(body);
    } else {
      console.log("Got an error: ", error, ", status code: ", response);
  }).on('complete', function() {
    if (data != undefined)

Now we will implement the route which takes product id as the parameter and returns product details using the helper function we implemented before:

app.get('/product', function(req, res) {
  helper.getProductDetails(req.param('productId'), function(data) {
    var details = {
      'productId': req.param('productId'),
      'price': data.productBaseInfoV1.flipkartSpecialPrice.amount,
      'name': data.productBaseInfoV1.title,
      'imageurls': data.productBaseInfoV1.imageUrls

Step 3: Alert user when the price condition is met

When a user enters the condition through our chrome extension UI ( i.e press get notification button), we need to store it. We will be creating index_product helper function in helper.js which inserts the product details into the Appbase. It takes two parameter product_id and isUpdated. We use get_product_details function to get the details of the product using product_id and then based on isUpdated flag we insert or update in the Appbase.

var Appbase = require('appbase-js');
var appbaseCredentials = require('./appbase_credentials.json')
  Function for indexing the product detail into appbase.
module.exports.indexProduct = function(productId) {
  this.getProductDetails(productId, function(data) {
    var price = data.productBaseInfo.productAttributes.sellingPrice.amount;
    var name = data.productBaseInfo.productAttributes.productBrand
    var appbaseRef = new Appbase(appbaseCredentials);
      type: appbaseCredentials.type,
      id: productId,
      body: {
        'price': price,
        'productId': productId,
        'name': name
    }).on('data', function(response) {
    }).on('error', function(error) {

POST /set_alert takes product_id and range as the input. We will be using searchStreamToURL function of Appbase which will set the webhooks on the condition which is mentioned in the query. It allow us to set an alert without polling for the result at regular interval. We are using sendgrid for sending the mail as soon as condition specified by the user is met.

app.get('/alert', function(req, res) {
  /* Starting polling for the requested product */
  var mailBody = "You have set the price alert for flipkart product {{{name}}}. Your condition has been matched and Price has reached to {{{price}}}";

  var requestObject = {
    type: appbaseCredentials.type,
    body: {
      "query": {
        "filtered": {
          "query": {
            "match": { "productId": req.param('productId') }
          "filter": {
            "range": {
              "price": {
                "lt": req.param('lte'),
                "gte": req.param('gte')

  var webhookObject = {
    'method': 'POST',
    'url': 'https://api.sendgrid.com/api/mail.send.json',
    'headers': {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': 'Bearer ' + sendgrid_api_key
    "count": 1,
    'string_body': 'to=' + req.param('email') + '&subject=Your Flipkart product price Alert&text=' + mailBody + '&from=yash@appbase.io'
  /* Starting stream search for the user condition */
  appbase.searchStreamToURL(requestObject, webhookObject).on('data', function(response) {
    console.log("Webhook has been configured : ", response);
  }).on('error', function(error) {
    console.log("searchStreamToURL() failed with: ", error)

searchStreamToURL() subscribes to search query results on new document inserts and then send the POST request to the endpoint of your choice. 

We will write the code for the app to starts a server and listens on port 8081 for connections. The app responds with our routes for requests to the URL be mentioned above. For every other path, it will respond with a 404 Not Found.

var server = app.listen(process.env.PORT || 8081, '', function() {
  var host = server.address().address;
  var port = server.address().port;
  console.log('Flipkart extension backend app listening at http://%s:%s', host, port);

Step 4: Poll Flipkart API for price changes

We will now define polling.js which is responsible for polling Flipkart’s server to fetch current price of all the products in our database.

We will define start_polling function which takes product_id as the argument and starts the polling for that product. It calls index_product at the interval for 1000 seconds which can be changed. We call index_product with isUpdate flag as true which fetches the product detail and updates in the Appbase with the new value. 

  Requiring necessary helpers.
var Appbase = require('appbase-js');
var helper = require("./helper.js");

  Including appbase credentials stored in json file.
var appbase_credentials = require('./appbase_credentials.json');

  Appbase Credentials. Just make new account at appbase and configure it according to your account.
  Creating object of appbase, passing appbase_credentials.
var appbaseRef = new Appbase(appbase_credentials);

var productList = []
    This function is for starting polling of all the productsand storing it into the appbase databse.
    The time interval of polling is set to 1000 seconds.
function startPolling() {
  function poll() {
    setTimeout(function() {
      for (productId in productList) {
        console.log("Starting polling for the product with Id: " + productList[productId]);
    }, 1000000);

We will define fetchProducts function which is our main function responsible for fetching all the products from Appbase for which polling is to be started.

At the end, we will make a call to fetchProducts function.

function fetchProducts() {
  var requestObject = {
    type: appbase_credentials.type,
    body: {
      query: {
        match_all: {}
  appbaseRef.search(requestObject).on('data', function(response) {
    productList = response.hits.hits.map(function(hit) {
      return hit._id;
    appbaseRef.searchStream(requestObject).on('data', function(stream) {
      console.log("Starting polling for new product streamed: " + stream._id);
    }).on('error', function(error) {
      console.log("searchStream() failed with: ", error);
  }).on('error', function(error) {
    console.log("search() failed with: ", error)

  Call to the starter function.

Step 5: Running We will run index.js after which our chrome extension can intreact with the server

node index.js

We will also run polling.js which will keep the price of the products in our database updated with the current price

node polling.js

Trying it out It’s really easy to test a new extension in Chrome. Type “chrome://extensions” in a tab to bring up the extensions page.

Once on this page, check “Developer mode” to enable loading unpacked extensions. This will allow you to load your extension from a folder. Finally, click “Load unpacked extension” or simply drag the “price-monitoring-frontend” folder onto the page to load up the extension. You should immediately see the extension show up as a Browser Action with your icon in the toolbar window of the current tab.

To test out the extension, navigate to a product on Flipkart that you want to monitor. Then, go ahead and click the icon for our chrome extension. When the HTML page comes up, set the price range, your email address and “Get Notification” and you will receive email notification when your price range condition is met.

Here is the link to the repository if you don’t want to copy paste from here and clone directly:

Chrome extension Demo

Chrome extension code

Backend module