Hire Us
How we saved on Mixpanel

How we saved $650 on Mixpanel monthly

We got acquainted with Mixpanel as a data analytics tool after trying out the Bitcoin Code App pretty long time ago and integrated it for few our clients.

During last months we started active usage of Mixpanel integration on Railsware Labs products, like Smart Checklist add-on for JIRA, Mailtrap.io and even at railsware.com website to see our leads flow and behavior. We were quite happy with functionality service provided out of the box.

Until the end of Feb, when the following billing period was approaching to its end. We were quite surprised to see how much $ we had to pay for latest month with latest Mixpanel pricing tiers. Around 900 USD?!

Save 650usd on Mixpanel

It would be ok if we had used this data analytics on revenue generating services/products. But as long as products we were running here were rather experiments out of labs division it just didn’t pay the bill.

As Mixpanel provides subscription plans per Events and People we decided to optimise the most expensive part of tracking. We decided to remove all People profiles – they didn’t give us much value, so tracking them in the system was just overhead.

Plan was as follows

  • find people in Mixpanel Database falling under our filtering conditions
  • remove them

Looks too easy!

The thing is that Mixpanel doesn’t provide batch profiles removal functionality via UI. So we used mixpanel-engage-post tool that allows to batch-delete via API taking JSON as an input data.

Fortunately Mixpanel service also provides a pretty good custom reporting approach through JQL (JavaScript Query Language).

Regardless JQL flexibility and benefits of getting raw Mixpanel data it requires from user some learning and adaptation time. As if you used to write SQL queries and JQL approach and constructions are different.

Resulting JQL report

function main() {
   var now = new Date();
   var ntydaysAgo = (new Date( now - 360 * 1000 * 60 * 60 * 24 ));

  return join(
    Events({
       from_date: ntydaysAgo.toISOString().substring(0, 10),
       to_date: now.toISOString().substring(0, 10),
    }),
    People()
    )

  // remove all tuples without event, user or email
  .filter(function(tuple) {
    return tuple.user &&
          tuple.event &&
          tuple.user.email === undefined;
  })
  
  .groupByUser(function(state, tuples) {
      state = tuples[0].user.properties;

      var perEventCounts = tuples.reduce(
        (r, tuple)=> {
          r["event_"+tuple.event.name]=(r["event_"+tuple.event.name] || 0) + 1;
          return r;
        },
        {}
      );
      perEventCounts.events_all_selected = tuples.length;
      state = Object.assign(state, perEventCounts);
      
      return state;
  })
  // Get users with less than 50 events tracked
  .filter ((state)=>state.value.events_all_selected < 50)
  .filter ((state)=>state.value.id !== undefined)
  .map((state)=>{ state.value.week = state.key[1]; return state})
  .map((state)=>state)
  .flatten();

  // Comment this line to get Raw list of User Profile data for backup
  .map((state)=>({"$distinct_id":state.value.id,"$delete":""}))
 }

Upon execution it returns in exactly same file format which is required by mixpanel-engage-post tool
e.g.

[
  {
    "$distinct_id": "12391",
    "$delete": ""
  },
  {
    "$distinct_id": "12408",
    "$delete": ""
  }
]

Here we decided to cut off all user profiles from Railsware Website tracking which:

  • during 1 year
  • made less than 50 events
  • and are anonymous and don’t have email property set

Then do proper setup of mixpanel-engage-post tool, put resulting JSON in proper place and run

cat profiles-to-delete.json | engagepost

Few good things to consider

  1. You may want to have backup and save your users’ data before removing them. In our case – just comment last string in JQL report. Run it and save CSV. You can put it back to Mixpanel if (occasionally) you need to get info about your collected users and relevant events back.
  2. Obviously it’s better to optimize Mixpanel events and users tracking on front-end side. In our case – we might do user identification only when it falls under our needed conditions, so we skip collecting unrelevant ghost, bots profiles.

Per our report we filtered out 60k redundant user profiles.
And finally, after cleaning up we reduced monthly subscription costs from $650/month (for 100-300k users) to $150/month (for 50k users)!

Pretty great, huh?

Leave comment if you want to get more Product Marketing hacks we are constantly discovering in Railsware Labs!