Skip to content

Instantly share code, notes, and snippets.

@brandonmwest
Last active June 21, 2017 15:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brandonmwest/9e37c0bcf73ebd2e5f4e0defc6b45a78 to your computer and use it in GitHub Desktop.
Save brandonmwest/9e37c0bcf73ebd2e5f4e0defc6b45a78 to your computer and use it in GitHub Desktop.
RA + Node.js tutorial draft

Introduction

Today we're going to build a node.js application to collect email addresses using Kickbox. We'll be using Express and Request on the server side, and jQuery on the client.

We'll be using Glitch during this tutorial, because it provides an environment, editor, and hosting in one convenient package. There's an example of the completed project too. If you want to follow along in your own environment, all of the code will work.

What is Recipient Authentication?

Recipient Authentication makes it easy to collect email addresses the right way. We handle account activation, double email opt-in subscriptions, and password resets. We make sure the email gets delivered, send drip reminders, expire old links, handle opt-outs, and automatically add authenticated addresses to your email service provider or marketing platform.

Our JavaScript library protects your form from bots, spammers and auto-generated signups. And our API integrations make it easy to add the addresses you collect to your email marketing platform.

Prerequisites

  • A free Kickbox account. Create one here.
  • A Kickbox Authentication App Code. Create an authentication app. On the "Connect" page you'll see your app code.
  • A Kickbox API key that can access your new authentication app. Hit "Create New Key" on the connect page to create one. Choose "Sandbox" for now.

Keep your App Code and API Key nearby as we'll be using them soon.

Overview

Our project today has 3 components. These are:

  1. A view containing a form to capture an email address and a place to display progress.
  2. Some client-side JavaScript to fingerprint the client session
  3. A server-side route to call the kickbox API with the address, fingerprint, and app token

We'll start with some app scaffolding, create the view, add some client code, and wrap things up with the server-side.

Let's Get Going!

Woohoo! To start, fire up a fresh Glitch project. Glitch includes a boilerplate Express app straight away. If you're new to node or express, you might want to take a moment to look around the default code.

The first thing we need to do is add the other npm packages that we'll be using. Click on the package.json file in the left-hand list to open it. Next, click "Add Package" and add request and request-promise to your project. We're also going to use body-parser to handle API responses, so add that as well.

The entire package.json file should look like this:

{
  "//1": "describes your app and its dependencies",
  "//2": "https://docs.npmjs.com/files/package.json",
  "//3": "updating this file will download and update your packages",
  "name": "my-glitch-app",
  "version": "0.0.1",
  "description": "What am I about?",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.15.3",
    "request-promise": "^4.2.1",
    "body-parser": "^1.17.2",
    "request": "^2.81.0"
  },
  "engines": {
    "node": "6.10.x"
  },
  "repository": {
    "url": "https://glitch.com/edit/#!/welcome-project"
  },
  "license": "MIT",
  "keywords": [
    "node",
    "glitch",
    "express"
  ]
}

Some Scaffolding...

First things first, open up .env and add a line with your Kickbox API key. (Don't worry, this file is not public on Glitch).

KICKBOX_KEY=live_613ea0f77aa319317a0ea1ef86b7a60fe036611633ca912f017435d3339125a8

Next, open up server.js. We're going to start fresh, so delete all the default contents.

First, let's add the dependencies.

var express = require('express');
var request = require('request-promise');
var bodyParser = require('body-parser');

And then let's get our express app ready to go.

//we'll use these later
var api_host = "https://api.kickbox.io/v2/";
var app_code = "YOUR KICKBOX APP CODE HERE";

var app = express(); //create a new express app

app.use(bodyParser.urlencoded({extended: false})); //use body-parser for JSON

app.use(express.static('public')); //use the 'public' folder for css, js, images... 

var listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});

That's a Nice View

Now let's head over to views/index.html. This is where we're going to add our email capture form and a container for our progress tracker.

<form>
  <h1>Sign Up</h1>
  <h2>Fill out the form below to get started.</h2>

  <label for="email">Email Address</label>
  <input required type="email" name="email"/>
  <br/><br/>
  <button type="submit">
    Submit
  </button>
</form>

<div id="tracker"></div>

And we are going to add one additional required client-side script file. This file generates a fingerprint, allowing Kickbox to differentiate between legitimate users and malicious users (bulk account creators, bots, spammers, etc).

<script type="text/javascript" src="https://kickbox.io/authenticate/1/release.js"></script>

The entire views/index.html file should look like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Kickbox Email Capture Demo</title>
    <link rel="stylesheet" href="/style.css">
  </head>
  <body>
    
    <form>
      <h1>Sign Up</h1>
      <h2>Fill out the form below to get started.</h2>
      
      <label for="email">Email Address</label>
      <input required type="email" name="email"/>
      <br/><br/>
      <button type="submit">
        Submit
      </button>
    </form>
 
	  <div id="tracker"></div>
	
    <script src="https://code.jquery.com/jquery-2.2.1.min.js"
            integrity="sha256-gvQgAFzTH6trSrAWoH1iPo9Xc96QxSZ3feW6kem+O00="
            crossorigin="anonymous"></script>
    <script src="https://kickbox.io/authenticate/1/release.js"></script>
    <script src="/client.js"></script>
  </body>
</html>

Adding a Route

Now that we've got an index.html view with an email capture form, we need to tell our app how to serve it via routing.

Let's open server.js again. Before the var listener=... line, we're going to define our first route.

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

Now click the Show Live button in your project. You should see the rendered index.html view with the email capture form.

Client-side Code

Now let's make that form do some stuff. Open up public/client.js and clear out contents of the existing function.

Our client side code will do four things.

  1. Handle the form's submit event.
  2. Generate a fingerprint from the provided email address.
  3. Send the data to our server-side code
  4. Show the Kickbox email tracker

Let's get #1 sorted out first.

$(function() {
  //Your Recipient Authentication auth code
  var kickbox_app_code = "YOUR KICKBOX APP CODE";
  var email;
  
   $('form').submit(function(event) {
    //only prevent the default submit action if the form is valid
    //otherwise, let it proceed and fail, so we get native HTML5 validation
    if(self.form[0].checkValidity()) {
      event.preventDefault();
    }
    
    //get the provided email address
    email = $('input').val();
    
    //get the fingerprint, call our server-code, display tracker
    Kickbox.fingerprint(
    {
      app: kickbox_app_code, //your kickbox authentication app code
      email: email, // Email address to authenticate
      onSuccess: fingerprintSuccess,
      onError: function(err) {
        alert(err);
      }
    });
  });
});

Let's jump over to the server-side and revisit the client-side later.

Server-side Code

We need to define a route to handle the request from the client-side code and then use the provided email address and fingerprint to call the Kickbox API.

Let's go back to server.js and define another route. This time, we'll be handling a POST request to the /authenticate route.

app.post("/authenticate", (req, response) => { 
  var email = req.body.email;
  var kickbox_app_code = req.body.kickbox_app_code;
  var fingerprint = req.body.fingerprint;
  
  //once defined, this method will return our API call options
  var kickbox_call = getKickboxCall(req.body.email, req.body.fingerprint, req.body.kickbox_app_code);
  
  // make the call and handle any errors
  // after the request is done, send the API response directly to the client (even if it errors)
  request(kickbox_call).then(function(result){
    response.send(result);
  }).catch(function(err){
    response.send(err.response);
  });
});

Our route is created. Now let's define that getKickboxCall that generates the necessary options we need to pass to request-promise.

var getKickboxCall = function(email, fingerprint, kickbox_app_code)
{
  var kickboxCall = {
    uri: api_host + "authenticate" + "/" + kickbox_app_code,
    method: "POST",
    form: {
      apikey: process.env.KICKBOX_KEY,
      email: email,
      fingerprint: fingerprint
    },
    json: true
  };

  return kickboxCall;
}

Nice work, the server-side is good to go! Let's take a look at the whole server.js file:

var express = require('express');
var request = require('request-promise');
var bodyParser = require('body-parser');

//we'll use these later
var api_host = "https://api.kickbox.io/v2/";
var app_code = "YOUR KICKBOX APP CODE HERE";

var app = express(); //create a new express app

app.use(bodyParser.urlencoded({extended: false})); //use body-parser for JSON

app.use(express.static('public')); //use the 'public' folder for css, js, images... 

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

app.post("/authenticate", (req, response) => { 
  var email = req.body.email;
  var kickbox_app_code = req.body.kickbox_app_code;
  var fingerprint = req.body.fingerprint;
  
  //once defined, this method will return our API call options
  var kickbox_call = getKickboxCall(req.body.email, req.body.fingerprint, req.body.kickbox_app_code);
  
  // make the call and handle any errors
  // after the request is done, send the API response directly to the client (even if it errors)
  request(kickbox_call).then(function(result){
    response.send(result);
  }).catch(function(err){
    response.send(err.response);
  });
});

var getKickboxCall = function(email, fingerprint, kickbox_app_code)
{
  var kickboxCall = {
    uri: api_host + "authenticate" + "/" + kickbox_app_code,
    method: "POST",
    form: {
      apikey: process.env.KICKBOX_KEY,
      email: email,
      fingerprint: fingerprint
    },
    json: true
  };

  return kickboxCall;
}

var listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});

Finishing up the Client Code

Let's jump back over to client.js and finish up.

We need to generate a fingerprint and send it to Kickbox. The Kickbox.fingerprint() call requires three things: an email, an app code, and an onSuccess callback function.

Our onSuccess callback is going to POST to the /authenticate route we created in server.js. Let's write that now.

var fingerprintSuccess = function(fingerprint) {
  //make a post to our /authenticate route
  $.post( "/authenticate", 
    { 
      email: email, 
      fingerprint: fingerprint, 
      kickbox_app_code: kickbox_app_code 
    }, 
    //handle the response
    function(response){
    //do this if something goes wrong
      if (response.success != true) {
        alert(response.body.message);  
        return;
      }

      //get the tracking token from the API response
      var track_token = response.track_token;        

      //show the kickbox email tracker
      Kickbox.track({
        app: kickbox_app_code,
        token: track_token,
        element: $('#tracker')[0]
      });
    });
  }

We're almost there. Let's go to our form submit handler and remove the TODO.

//Your Recipient Authentication auth code
var kickbox_app_code = "YOUR KICKBOX APP CODE";

 $('form').submit(function(event) {
  //prevent default form submission handler
  event.preventDefault();
  
  //get the provided email address
    var email = $('input').val();
  
  Kickbox.fingerprint({
    app: kickbox_app_code, //your kickbox authentication app code
    email: email, // Email address to authenticate
    onSuccess: fingerprintSuccess,
    onError: function(err) {
      alert(err);
    }
  });
}

And that's it for the client side. The completed public/client.js file should look similar to this:

$(function() {
  var email;
  
  //Your Recipient Authentication auth code
  var kickbox_app_code = "YOUR KICKBOX APP CODE";

   $('form').submit(function(event) {
    //prevent default form submission handler
    event.preventDefault();
    
    //get the provided email address
    email = $('input').val();
    
    //get the fingerprint, call our server-code, display tracker
    Kickbox.fingerprint(
    {
      app: kickbox_app_code, //your kickbox authentication app code
      email: email, // Email address to authenticate
      onSuccess: fingerprintSuccess,
      onError: function(err) {
        alert(err);
      }
    });
  });

var fingerprintSuccess = function(fingerprint) {
  //make a post to our /authenticate route
  $.post( "/authenticate", 
    { 
      email: email, 
      fingerprint: fingerprint, 
      kickbox_app_code: kickbox_app_code 
    }, 
    //handle the response
    function(response){
    //do this if something goes wrong
      if (response.success != true) {
        alert(response.body.message);  
        return;
      }

      //get the tracking token from the API response
      var track_token = response.track_token;        

      //show the kickbox email tracker
      Kickbox.track({
        app: kickbox_app_code,
        token: track_token,
        element: $('#tracker')[0]
      });
    });
  }
});

We're done! Click "Show Live." Fill out the form with an email address you control, then watch the tracker as you move through the authentication process.

Authentication Tracker

You will also see some activity show up on your Authentication dashboard.

Next Steps

Now that you've got the basics working, there are several ways to handle authentication status. You can respond programmatically to new authentication events via webhook or redirect the user to a page of your choosing after authentication. And there's an API endpoint for retrieving authentication status.

Want to automatically add the emails you collect to a list on your email service provider's platform? Go to the advanced settings sections of your Authentication app and click "Mailing Lists."

And in the Advanced Settings section of the website, you can configure drip reminders and link expiration.

If you got any questions or comments, please get in touch! We're here to help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment