No commit activity in last 3 years
No release in over 3 years
Mixpanel client ORM for easy querying and reporting data.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

 Project Readme

Mixpanel Magic Lamp

Gem Version

Rub the magic lamp and your desired Mixpanel ORM will appear!

If you're using Mixpanel for your web site analytics you probably thought in make reports exporting your data through any Mixpanel API client. This gem is your answer for not overwarming your head with so many doc, and it will remind you to ActiveRecord.

Install

You can install this gem by

$ gem install mixpanel_magic_lamp

Or bundle it on your app by adding this line at your Gemfile

gem 'mixpanel_magic_lamp'

Configuration

To setup this gem you should add API keys and other config:

MixpanelMagicLamp.configure do |config|
  # Set your API Key/Secret
  config.api_key     = "YOUR MIXPANEL API KEY"
  config.api_secret  = "YOUR MIXPANEL API SECRET"

  # Run query in parallel (recomended for better performance)
  config.parallel = true

  # Default interval on from/to dates when dates are not provided
  config.interval = 30
end

Rails config generator

Copy base config file on your Rails app by

rails generate mixpanel_magic_lamp:config

Build your query

The most interesting feature from this library is probably the query builder, that let you to build an 'ActiveRecord' like query to run API queries, it will remind you to the Mixpanel UI:

where

Start any query with this keyword, and extend is as long as you need. This method accept a hash as first parameter where each pair of key/value are traslated to "key == value" (equals_to), a second parameter may change union word:

Mixpanel.where(country: 'Spain', gender: 'Female').to_s
=> "(properties[\"country\"] == \"Spain\" and properties[\"gender\"] == \"Female\")"

Mixpanel.where({country: 'Spain', gender: 'Female'}, 'or').to_s
=> "(properties[\"country\"] == \"Spain\" or properties[\"gender\"] == \"Female\")"

Then you may append any existent query build to complete your API query:

Mixpanel.where(country: 'Spain').or.is_set('source').to_s
=> "(properties[\"country\"] == \"Spain\") or (defined (properties[\"source\"]))"

### and/or Concat as many query builders as you need with and and or operators:

Mixpanel.where(country: "Spain", browser: "Chrome")
        .and.is_set('device_type')
        .and.does_not_equal(user_type: 'bot')
        .and.contains(url: '/sales')
=> "(properties[\"country\"] == \"Spain\" and properties[\"browser\"] == \"Chrome\") and (defined (properties[\"device_type\"])) and (properties[\"user_type\"] != \"bot\") and (\"/sales\" in (properties[\"url\"]))">

on

Use it as by statement on your UI, in order to group segmentation:

Mixpanel.on('country')
=> "properties[\"country\"]"

Builders

equals

Mixpanel.where.and.equals(country: 'Spain', user_type: 'human').to_s
=> "(properties[\"country\"] == \"Spain\" and properties[\"user_type\"] == \"human\")"

does_not_equal

Mixpanel.where.and.does_not_equal(country: 'Spain', user_type: 'human')
=> "(properties[\"country\"] != \"Spain\" and properties[\"user_type\"] != \"human\")"

contains

Mixpanel.where.and.contains(country: 'Spain', user_type: 'human').to_s
=> "(\"Spain\" in (properties[\"country\"]) and \"human\" in (properties[\"user_type\"]))"

does_not_contain

Mixpanel.where.and.does_not_contain(country: 'Spain', user_type: 'human').to_s
=> "(not \"Spain\" in (properties[\"country\"]) and not \"human\" in (properties[\"user_type\"]))"

is_set

Mixpanel.where.and.is_set(['country', 'user_type']).to_s
=> "(defined (properties[\"country\"]) and defined (properties[\"user_type\"]))"

is_not_set

Mixpanel.where.and.is_not_set(['country', 'user_type']).to_s
=> "(not defined (properties[\"country\"]) and not defined (properties[\"user_type\"]))"

Actions

Mixpanel API client has a lot of possible actions, so far these are the supported actions:

Segmentation

Classic Mixpanel segmentation action, where you can specify event name, from/to dates and any conditions you want. Prepare and run as many request in parallel you need

interface = Mixpanel::Interface.new

page_visits_query = Mixpanel.where("product" => 'Finances')
                            .and.is_set("subproduct")
page_visits  = interface.segmentation('Page visit', { from: Data.parse('2015-01-31'),
                                                      to: Date.today },
                                                    { where: page_visits_query })


login_clicks_query = Mixpanel.where("device_type" => 'mobile')
login_clicks = interface.segmentation('Login', { from: Data.parse('2015-04-01'),
                                                 to: Date.today },
                                               { where: login_clicks_query })

# Run all the queued queries
interface.run!

# Present your data...
p page_visits[:data]
p login_clicks[:data]

Segmentation by

Same as segmentation but grouping the output by any property you want to.

interface = Mixpanel::Interface.new

page_visits_query = Mixpanel.where("product" => 'Finances')
                            .and.is_set("subproduct")
page_visits  = interface.segmentation('Page visit', { from: Data.parse('2015-01-31'),
                                                      to: Date.today },
                                                    { where: page_visits_query,
                                                      on: Mixpanel.on('device_type') })

# Run all the queued queries
interface.run!

# Present your data...
p page_visits[:data]

Your own interface

Now you master all the above concepts, the best thing you can do is to build your own interface model for extracting your reports:

module Mixpanel
  class LandingPagesInterface < Mixpanel::Interface

    def initialize
      super()
    end

    def views(from: nil, to: nil)
      where_context = Mixpanel.where('page_type' => 'landing')
                              .and.is_set('device_type')

      segmentation 'Page view', { from: from, to: to },
                                { where: where_context }
    end

    def views_by_devices(from: nil, to: nil)
      where_context = Mixpanel.where('page_type' => 'landing')
                              .and.is_set('device_type')

      segmentation_interval 'Page view', { from: from, to: to },
                                         { where: where_context,
                                           on: Mixpanel.on('device_type') }
    end

  end
end

# Initialize your interface
landing_interface = Mixpanel::LandingPagesInterface.new

# Prepare all the queries
landing_last_week_views = landing_interface.views(from: 14.days.ago, to: 7.days.ago)
landing_this_week_views = landing_interface.views(from: 6.days.ago, to: Date.today)
landing_last_week_view_by_devices = landing_interface.views_by_devices(from: 14.days.ago, to: 7.days.ago)

# Run all the queries
landing_interface.run!

# Retrieve your data!
p landing_last_week_views[:data]
p landing_this_week_views[:data]
p landing_last_week_view_by_devices[:data]

On top of mixpanel_client Gem

This ORM is build on top mixpanel_client gem.

You'll find the oficial mixpanel info here.

Monkey patching

On this gem you'll find a Mixpanel::Client class monkey patch to avoid exceptions raise when any of the parallel request fails, i.e all the requests will run until completion and return their correspondent HTTP status (error or success) and body as usual. See it here.

Contribution

If you have cool idea for improving this Gem or any bug fix just open a pull request and I'll be glad to have a look and merge it if seems fine.

License

This project rocks and uses MIT-LICENSE.