Sticky MPKnowledgeDrop

Get a List of all the Annotations You’ve Created in Mixpanel Using Node

  • 24 April 2020
  • 0 replies
  • 76 views
Get a List of all the Annotations You’ve Created in Mixpanel Using Node
Badge +1

Every week, we will release tips to help you get the most out of Mixpanel. Want to see more? Click here to see other #mpknowledgedrop articles.

 

A few weeks ago my colleague Cherise asked for help pulling a list of all her annotations in Mixpanel’s internal Mixpanel project.  After working on this together, we figured that users in QBQ might be curious about this as well!  Here’s the series of steps I thought through that can help you pull this list.

 

Note: this will require using an undocumented API, and we can’t guarantee backwards compatibility moving forward.

 

First, I checked our documented API for pulling annotations from a specific project here.  Unfortunately the data returned from the API looks like so:

 

{
"annotations":[
{"date": "2014-05-23 00:00:00", "project_id": 23880, "id": 148, "description": "Launched v2.0 of product"},
{"date": "2014-05-29 00:00:00", "project_id": 23880, "id": 150, "description": "Streamlined registration process"}
],
"error": false
}

 

As you can see, this request does not return the name of the user who created the annotation.  But since the Mixpanel user interface does display the user’s name along with the annotation, it must be pulling in that data from somewhere.  This led me to a trick I learned early on at Mixpanel -- to look at the requests that the Mixpanel UI makes to our APIs to see how to replicate them.

 

First, I opened the developer console in Chrome (how to open dev console here).  Then I looked at a line graph view in Insights and saw the corresponding requests being made:

 

One of the requests had “annotations” in the name, and the response (found in the response tab) looked like this:

 

Voila!  This request contains the same information as the documented API but also includes a nested object for each annotation specifying the user who created it.  

 

Let’s copy the logic of the request into a node script so we can start tinkering with the results.  

 

The easiest way I’ve found to do this is to use Chrome’s “Copy as cURL” feature:

 

Using “Copy as cURL” guarantees that if you paste the request in your computer terminal, you’ll get the same response you see in the developer console.  

 

The next step is to convert this to Node.  Rather than doing it the long way, I typically use this cURL to node converter.

 

In this case, the headers are a bit convoluted (since they contain cookie information, etc.)  But I happen to know the only header that’s required is “authorization”.  Node below:

 

Note: be very careful showing people your bearer token associated with 'authorization' -- if they’re clever, they can use it to pull information out of Mixpanel without an account.

var request = require('request');

var headers = {
    'authorization': 'Bearer <your bearer token>',
};

var options = {
    url: 'https://mixpanel.com/api/app/<your project id>/annotations/?fromDate=2020-03-24&toDate=2020-04-23',
    headers: headers
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);

 

Try running this script to make sure you get the same results you see in Chrome.  (You should.)

 

Next, you’ll have to write a function to format the results and pull just the subset of annotations that match a particular name.  If I’m looking for Cherise’s, my function will have to do the following:

  1. Convert the response to valid JSON

  2. Grab the nested array representing the annotations

  3. Loop through the array from step 2 and store Cherise’s annotations in a new array (I’m also checking to make sure the user key exists before checking for the name match since older annotations didn’t have user information)

  4. Return the new array

 

Here’s what that looks like in node:

function processResults(body) {
    var json = JSON.parse(body);
    var results = json.results;
    var temp = [];
    for (var i = 0; i < results.length; i++) {
        if (results[i].user && results[i].user.first_name == 'Cherise' && results[i].user.last_name == 'Goode')
            temp.push(results[i]);
    }
    return temp;
}

Now, in the callback, instead of

console.log(body);

We need

console.log(processResults(body));

 

Alright, we’re almost finished (you can run the script now to see how close we are).  The last factor is the date range.  If you look at the URL in the options parameter, you’ll see it ends with 

fromDate=2020-03-24&toDate=2020-04-23

Simply change this to the date range you care about, and re-run the script.  We should be good to go.

 

The above technique has come in quite handy throughout my years at Mixpanel, so hopefully it’s given you all some ideas for interacting with Mixpanel in a more advanced way.

 

Full script below:

var request = require('request');

var headers = {
    'authorization': 'Bearer <your bearer token>',
};

var options = {
    url: 'https://mixpanel.com/api/app/<your project id>/annotations/?fromDate=2018-01-01&toDate=2020-04-23',
    headers: headers
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(processResults(body));
    }
}

request(options, callback);

function processResults(body) {
    var json = JSON.parse(body);
    var results = json.results;
    var temp = [];
    for (var i = 0; i < results.length; i++) {
        if (results[i].user && results[i].user.first_name == 'Cherise' && results[i].user.last_name == 'Goode')
            temp.push(results[i]);
    }
    return temp;
}

 


0 replies

Be the first to reply!

Reply