Improve your drip campaigns with Mixpanel and FullContact

By using FullContact to push user profile data into Mixpanel we’re able to make targeting and tracking more powerful. We can target drip marketing campaigns more precisely based on where our users work, as well as their social profiles, location or age.

For those that are unfamiliar, Mixpanel helps you track your users and customers as they use your application, hopefully providing insight into how to increase conversion rates (“revenue analytics”). FullContact is a cool little API that takes an email address and provides lots of information about the person behind that address — his or her social network profiles, places of employment and some basic demographic information.

We are trying to get to a place where we can trigger notifications based on personal attributes instead of just when they signed up. Here is an example of targeting made possible by FullContact and Mixpanel:

image

The following is a short tutorial on using the FullContact API to push user data into Mixpanel. 

First off, this is what a user might look like in your Mixpanel project:

{
    "email": "sean@embed.ly",
    "plan": "basic",
    "date_joined": "May 1, 2012",
    "last_login": "May 10, 2013"
}

This information is probably populated by your frontend via the Mixpanel javascript library, but it’s perfectly reasonable to do it in the backend as well. Fullcontact, however, is a separate API that you’ll have to call on your backend. Looking up an email address is very straightforward via its HTTP API:

$ curl "http://api.fullcontact.com/v2/person.json?email=sean@embed.ly&apiKey=YOURKEY"

{
  "status": 200,
  "likelihood": 0.89,
  "requestId": "aa2f9f2c-57b8-48ab-811b-1be24aa652c8",
  "photos": 
  ...
  "demographics": {
    "locationGeneral": "Boston",
    "gender": "Male"
  },
  ...
}

Take a look at the full response if you’d like to see what kind of information it can provide. Pretty simple, although there are a couple details to keep in mind:

  • Ocassionally Fullcontact will return HTTP 202 which indicates your search has been queued and that you should retry the request in a few minutes
  • A status code of 404 means the query has run and no information was found
  • Fullcontact will rate limit your requests based on your plan

This means you’ll want to do your lookups in batches, which might look something like this:

def fullcontact_lookup(emails, api_key):
    results = {}
    to_lookup = set(emails)
    api_format = 'http://api.fullcontact.com/v2/person.json?email=%s&apiKey=%s'
    while len(to_lookup) > 0:
        # make a copy so we can delete from the set while we iterate
        for email in to_lookup.copy():
            api = api_format % (email, api_key)
            response = json.loads(requests.get(api).text)
            if response['status'] == 200:
                results[email] = response
                to_lookup.remove(email)
            elif response['status'] == 404:
                results[email] = None
                to_lookup.remove(email)
            elif response['status'] == 202:
                # keep it around to give it another go
                pass
            else:
                raise ValueError('Unexpected response from fullcontact: %s' %
                    json.dumps(response))
        # give fullcontact a minute to run some queries
        time.sleep(60)
    return results

Now we need to actually stuff this data into Mixpanel. Unfortunately, naively running fullcontact_lookup against your entire database every night will be expensive, as Fullcontact charges per successful request. What we can do is add a property to each person called, say, fullcontact_version that keeps track of who has been queried. This can be an integer that gets incremented each time you change your schema, so you can just run the people with fullcontact_version != current_version. Treat the code below as pseudo-code; if you’d like to see the nitty gritty Mixpanel API details check out their docs.

def go(fullcontact_version):
    to_update = get_with_different_version(fullcontact_version)
    all_info = fullcontact_lookup(to_update)
    for person in to_update:
        info = all_info[person['email']]
        person['fullcontact_version'] = fullcontact_version
        if info:
            person['age'] = info.get('demographics', {}).get('age')
            # add more properties as you see fit
        save_person_to_mixpanel(person)

And there it is! With this small amount of effort you can get greater insight into who your users are and the ability to communicate with them more efficiently.

Posted 1 year ago by thejohnnest
Embed This