The recent acquisition of Trello by Atlassian, who own Jira, reminded me how much I like Trello. I use it for personal to-do lists as well as for product development, as a light-weight Scrum or Kanban board (which I guess is Atlassian’s angle in buying it). I really hope that Atlassian nurture this product! Anyway, I wanted to write about how I used its API to help prototype a new customer success process at a company I was working at.

As product manager for a B2B saas product, I wanted to see if we could improve the conversion rate from trial customers to paying customers (and their retention thereafter). Like many saas products, we offered a 30 day free trial. During the trial period we sent out automated onboarding emails at certain intervals. However, I wanted to try a more personal approach and pro-actively contact customers, offering them help with getting set up so that they were more likely to get value out of our product.

I wasn’t quite sure what the workflow would look like and wanted to be able to stay flexible until we knew this was a worthwhile change. We set up a new Trello board and automatically created a card for each new trial customer. This was achieved by having an internal system send out an email to the Trello board, which then created a card for the email in a list called ‘New Trial Customer’. The board then had a number of other lists, each of which represented a step in our process (‘Leads’, ‘First Follow-up’ and so on). In this blog post I want to concentrate on just the first step: from ‘New Trial Customer’ to ‘Leads’.

As I said, we automatically created a card for each new trial customer. The goal at this step was effectively to ‘triage’ our customers by:

  1. Filtering out certain customers because we knew that we had a negligable chance of converting them to paying customers (and we wanted to focus our efforts);
  2. Automatically enriching the remaining customers with salient information about their company, where available.

Ideally, we would have done this in the aforementioned internal system but that wasn’t feasible. Luckily, Trello has a nice API so I wrote a small node.js program. All the program does is respond to webhook notifications when a change is made to a Trello model (such as a list, or card). In my case, I wanted to be notified each time a new card was created in the ‘New Trial Customer’ list. Therefore, I created a webhook for the modelID of that list. (See Trello’s webhook documentation for more information about using webhooks.)

The app.js for my file looked like this:

var config = require('./config');
var Trello = require('node-trello');
var t = new Trello(config.trello.key, config.trello.token);

var express = require('express');
var bodyParser = require('body-parser');
var clearbit = require('clearbit')(config.clearbit.key);
var company = clearbit.Company;
var app = express();
var jsonParser = bodyParser.json();

//When creating a trello webhook, trello runs an HTTP HEAD request on the URL and expects a 200 status code
app.head('/newCard', function(request, response) {
	response.sendStatus(200);
	console.log("webhook creation request");
});

...

var port = process.env.PORT || 8888;
app.listen(port);
console.log("Server has started, listening on port " + port);

Once I had my webhook up and running, I wrote some code to respond to the webhook notifications. As I said above, the first step was to ‘triage’ the card and filter out some customers. ‘Filtering out’ meant just archiving the card:

//get the card id for new card and triage
app.post('/newCard', jsonParser, function(request, response){
  response.sendStatus(200);
  if (request.body.action.type == "emailCard") {
	getCardID(triageCard, request.body.action.id);
  }
});

function getCardID(callback, actionID) {
	console.log("Get cardID for actionID: " + actionID);
	t.get("/1/actions/".concat(actionID,"/card"), function(err, data) {
		if (err) throw err;
		callback(data.id);
	});
};

function triageCard(cardID) {
	t.get("/1/cards/".concat(cardID,"/desc"), function(err, data) {
		
		// triage logic omitted
		// this function just decided whether we wanted to:
		// a) archiveCard(cardID); or
		// b) getCompanyInfo(cardID, companyDomain)
		// where companyDomain was a domain extracted from an email address

	});
};

function archiveCard(cardID) {
	t.put("/1/cards/".concat(cardID,"/closed"), { value: "true" }, function(err, data) {
		if (err) throw err;
	});
}

So how did we get company information with just a domain name?

Enter Clearbit. Clearbit is an API which lets you (among other things) look up company information with just a domain name, or email address. They have great documentation and are free to try so I won’t describe the setup process.

With Clearbit up and running, I was able to call the service to look up a company and add the company information and logo (where available) to the Trello card. In the code below I only add 5 metrics, but the Clearbit enrichment api has over 85 data points which can be returned for a given company.

Once the card was ‘enriched’, it was moved to the ‘Leads’ list. (Where a company result was not returned by Clearbit, I added a label and left it in the ‘New trial customer’ list for manual inspection.)

function addCompanyNotFoundLabel(cardID) {
	t.post("/1/cards/".concat(cardID,"/idLabels"), { value: config.trello.nocompany_label }, function(err, data) {
		if (err) throw err;
	});
}

function getCompanyInfo(cardID, companyDomain) {
	company.find({domain: companyDomain, stream: true})
  		.then(function (company) {
    		createLeadCard(cardID, company);
  		})
  		.catch(company.NotFoundError, function (err) {
    		console.log('Company could not be found.');
    		addCompanyNotFoundLabel(cardID);
  		})
  		.catch(function (err) {
    		console.log('Bad/invalid request, unauthorized, Clearbit error, or failed request');
  		});
}

function createLeadCard(cardID, company) {

    var markdown = "";
    if (company.name !== null) markdown = markdown + "\n" + "* **Name**: " + company.name;
    if (company.site.url !== null) markdown = markdown + "\n" + "* **URL**: " + company.site.url;
    if (company.metrics.employees !== null) markdown = markdown + "\n" + "* **No. Employees**: " + company.metrics.employees;
    if (company.location !== null) markdown = markdown + "\n" + "* **Headquarters**: " + company.location;
    if (company.description !== null) markdown = markdown + "\n" + "* **Description**: " + company.description;


    //replace description with company information
	t.put("/1/cards/".concat(cardID,"/desc"), { value: markdown }, function(err, data) {
		if (err) throw err;
	});

	//add logo to the card if one available
	if (company.logo !== null) {
		t.post("/1/cards/".concat(cardID,"/attachments"), { url: company.logo }, function(err, data) {
			if (err) throw err;
		});
	}

	//move card to the leads list
	t.put("/1/cards/".concat(cardID,"/idList"), { value: config.trello.lead_list }, function(err, data) {
		if (err) throw err;
	});
}

Here’s what a card looks like (in its closed state) after Clearbit has returned company information and it has been moved to the Leads list:

Screenshot of closed Trello card

And here’s how it looks when you open it:

Screenshot of open Trello card

By looking at one of these cards, someone working in the customer support team can get a quick overview of salient details about the customer, such as their location and company size, before contacting them. They can then offer more relevant help and sales information based on this information.