├── .dockerignore ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── README.md ├── mixpanel ├── mixpanel-cli.js ├── package.json └── protocol.json /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !package.json 3 | !protocol.json 4 | !mixpanel-cli.js 5 | !mixpanel 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | scripts 2 | .env 3 | npm-debug.log 4 | yarn.lock 5 | user_ids.txt 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## 0.0.1 (2016-10-25) 3 | 4 | * docs(changelog): updated ([8c091ed](https://github.com/fgribreau/mixpanel-cli/commit/8c091ed)) 5 | * feat(🎩) ([b9012f9](https://github.com/fgribreau/mixpanel-cli/commit/b9012f9)) 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6-onbuild 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### mixpanel-cli - A command-line tool to query Mixpanel API 2 | 3 | ![deps](https://img.shields.io/david/fgribreau/mixpanel-cli.svg?style=flat) ![Version](https://img.shields.io/npm/v/mixpanel-cli.svg?style=flat) [![Docker hub](https://img.shields.io/docker/pulls/fgribreau/mixpanel-cli.svg)](https://hub.docker.com/r/fgribreau/mixpanel-cli/) [![available-for-advisory](https://img.shields.io/badge/available%20for%20consulting%20advisory-yes-ff69b4.svg?)](http://bit.ly/2c7uFJq) ![extra](https://img.shields.io/badge/actively%20maintained-yes-ff69b4.svg) [![Twitter Follow](https://img.shields.io/twitter/follow/fgribreau.svg?style=flat)](https://twitter.com/FGRibreau) [![Get help on Codementor](https://cdn.codementor.io/badges/get_help_github.svg)](https://www.codementor.io/francois-guillaume-ribreau?utm_source=github&utm_medium=button&utm_term=francois-guillaume-ribreau&utm_campaign=github) [![Slack](https://img.shields.io/badge/Slack-Join%20our%20tech%20community-17202A?logo=slack)](https://join.slack.com/t/fgribreau/shared_invite/zt-edpjwt2t-Zh39mDUMNQ0QOr9qOj~jrg) 4 | 5 | 6 | ## Shameless plug 7 | 8 | - [**Charts, simple as a URL**. No more server-side rendering pain, 1 url = 1 chart](https://image-charts.com?gh_mixpanel_cli) 9 | - [Looking for a free **Redis GUI**?](http://redsmin.com?gh_mixpanel_cli) [Or for **real-time alerting** & monitoring for Redis?](http://redsmin.com) 10 | 11 |

mixpanel cli

12 | 13 | ## Install (docker 🐳) 14 | 15 | Use this approach if you don't know/want to setup your NodeJS environment, that's what containers are good for. 16 | 17 | ```shell 18 | # open ~/.bashrc (or equivalent) 19 | nano ~/.bashrc 20 | 21 | # edit it 22 | function mixpanel(){ 23 | docker run -it --rm -e MIXPANEL_API_KEY=$MIXPANEL_API_KEY fgribreau/mixpanel-cli:latest ./mixpanel $@ 24 | } 25 | 26 | # save it 27 | 28 | # source it 29 | source ~/.bashrc 30 | 31 | # run it! 32 | mixpanel 33 | 34 | # done! 35 | ``` 36 | 37 | ## Install (NodeJS) 38 | 39 | ``` 40 | npm i mixpanel-cli -S 41 | ``` 42 | 43 | ## Currently supported 44 | 45 | ``` 46 | $ mixpanel 47 | 48 | Commands: 49 | track Track an event 50 | people.set Set properties on a user record 51 | people.set_once Set properties on a user record, only if they do not yet exist 52 | people.increment Increment/decrement numeric people analytics properties 53 | people.append Append a value to a list-valued people analytics property 54 | people.union Merge a given list with a list-valued people analytics property, excluding duplicate values 55 | people.track_charge Record that you have charged the current user a certain amount of money 56 | people.clear_charges Permanently clear all revenue report transactions from the current user's people analytics profile 57 | people.delete_user Permanently deletes the current people analytics profile from Mixpanel (using the current distinct_id) 58 | 59 | Options: 60 | -h, --help Show help [boolean] 61 | 62 | @FGRibreau - https://twitter.com/FGRibreau 63 | ``` 64 | 65 | ## Usage 66 | 67 | First thing first, expose your mixpanel api key ("Project settings" > "Token") through an environment variable `MIXPANEL_API_KEY`. 68 | 69 | ```shell 70 | export MIXPANEL_API_KEY="your_api_key" 71 | ``` 72 | 73 | 74 | ### Track event 75 | 76 | ```shell 77 | mixpanel track --distinct_id UNIQUE_USER_ID --event_name "User opened settings" --properties Country France Model "SM-T530" 78 | ``` 79 | 80 | ### Set property to user profile 81 | 82 | ```shell 83 | mixpanel people.set --distinct_id UNIQUE_USER_ID --prop MyProperty --to ValueToSet 84 | ``` 85 | 86 | ### Add a property to a list of users (sequential) 87 | 88 | ```shell 89 | echo "ID1\nID2" | xargs -I {ProfileID} mixpanel people.set --distinct_id {ProfileID} --prop MyProperty --to ValueToSet 90 | ``` 91 | 92 | ### Add a property to a list of users (parallel) 93 | 94 | Same as above but does `10` requests in parallel (`-P 10`)! 95 | 96 | ```shell 97 | cat user_ids.txt | xargs -P 10 -I {ProfileID} mixpanel people.set --distinct_id {ProfileID} --prop MyProperty --to ValueToSet 98 | ``` 99 | 100 | ## Todo 101 | 102 | - [ ] More examples / better documentation (even if the CLI is completely documented) 103 | - [ ] Tests 104 | 105 | 106 | ## [Changelog](/CHANGELOG.md) 107 | -------------------------------------------------------------------------------- /mixpanel: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('./mixpanel-cli'); 4 | -------------------------------------------------------------------------------- /mixpanel-cli.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Mixpanel = require('mixpanel'); 3 | const _ =require('lodash/fp'); 4 | const API_KEY = process.env.MIXPANEL_API_KEY; 5 | 6 | if(!API_KEY){ 7 | console.error('Environment variable "MIXPANEL_API_KEY" must be defined'); 8 | process.exit(1); 9 | } 10 | 11 | const mixpanel = Mixpanel.init(API_KEY, {protocol: 'https'}); 12 | 13 | mixpanel.config.debug = true; 14 | const log = console.log.bind(console); 15 | console.log = function(data){ // sigh... 16 | 17 | if(_.isPlainObject(data)){ 18 | const printedData = _.cloneDeep(data); 19 | printedData.$token = '** MASKED BY MIXPANEL-CLI 👻 **'; 20 | log(printedData); 21 | } 22 | }; 23 | 24 | const protocol = require('./protocol.json') // Oh yeah :) 25 | .filter(command => (command.method.name.includes('mixpanel.track') || command.method.name.includes('mixpanel.people')) && !command.method.name.includes('mixpanel.track_links') && !command.method.name.includes('mixpanel.track_forms')) // could be expanded in the futur 26 | .map(command => { 27 | // add unique_id to every methods 28 | command.method.arguments.unshift({ 29 | "name": "distinct_id", 30 | "type": "String", 31 | "requireIdentify": true, 32 | "isRequired": true, 33 | "description": "Identify a user with a unique ID" 34 | }); 35 | 36 | // remove mixpanel. 37 | command.method.name = command.method.name.replace('mixpanel.', ''); 38 | 39 | // map object values to key value pairs 40 | 41 | function noCallback(arg){ 42 | return arg.name !== 'callback'; 43 | } 44 | 45 | command.method.arguments = command.method.arguments 46 | .filter(noCallback) 47 | .map(arg => { 48 | if(arg.type === 'Object'){ 49 | arg.mixpanelType = 'array'; 50 | } else if(arg.type === 'Number'){ 51 | arg.mixpanelType = 'number'; 52 | } else if(arg.type === 'String' || arg.type === '*' || arg.type === 'Object or String'){ 53 | arg.mixpanelType = 'string'; 54 | } else { 55 | throw new Error(`Unsupported method argument type ${arg.type} for "${command.method.name}" : ${JSON.stringify(arg, null, 2)}`); 56 | } 57 | 58 | return arg; 59 | }); 60 | 61 | return command; 62 | }); 63 | 64 | 65 | const argv = require('yargs') 66 | .wrap(null) // specify no column limit (no right-align) 67 | .count('Usage: $0 [options]'); 68 | 69 | protocol.forEach(({method: {name, arguments:args}, description}) => { 70 | argv.command( 71 | name, 72 | description.split('.')[0], 73 | yargs => args.reduce(argToYargOption, yargs), 74 | runCommand 75 | ); 76 | }); 77 | 78 | const args = argv.help() 79 | .alias('h', 'help') 80 | .epilog('@FGRibreau - https://twitter.com/FGRibreau') 81 | .alias('v', 'verbose') 82 | .argv; 83 | 84 | if(args._.length === 0){ 85 | return argv.showHelp(); 86 | } 87 | 88 | function argToYargOption(yargs, arg){ 89 | return yargs.options(arg.name, { 90 | demand: arg.isRequired, 91 | describe: arg.description, 92 | type: arg.mixpanelType 93 | }) 94 | } 95 | 96 | 97 | function runCommand(argv){ 98 | const commandName = _.first(argv._); 99 | 100 | const method = _.find(api => api.method.name === commandName, protocol).method; 101 | 102 | // if the commands does not have any args, first parameter is distinct_id 103 | const args = method.arguments.filter(a => a.name !== 'distinct_id'); 104 | 105 | const mpCallCtx = _.get(_.initial(method.name.split('.')), mixpanel); 106 | const mpCall = _.get(method.name, mixpanel).bind(mpCallCtx); 107 | const mpCallback = (err) => { 108 | if(err){ 109 | console.error(err); 110 | throw err; 111 | } 112 | console.log('done'); 113 | }; 114 | 115 | if(args.length === 0){ 116 | return mpCall(argv.distinct_id, mpCallback); 117 | } 118 | 119 | if(method.name.includes('people')){ 120 | const peopleArgs = [argv.distinct_id].concat(args.map(arg => { 121 | return argv[arg.name]; 122 | })).concat(mpCallback); 123 | return mpCall.apply(null, peopleArgs); 124 | } 125 | 126 | const defaultArgs = _.initial(args).map(arg => { 127 | return argv[arg.name]; 128 | }) 129 | .concat(_.flow(_.chunk(2), _.fromPairs, _.tap(properties => properties.distinct_id = argv.distinct_id))(argv.properties || [])) 130 | .concat(mpCallback); 131 | 132 | return mpCall.apply(null, defaultArgs); 133 | } 134 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mixpanel-cli", 3 | "version": "1.0.3", 4 | "author": "Francois-Guillaume Ribreau (http://fgribreau.com/)", 5 | "engines": { 6 | "node": "6" 7 | }, 8 | "scripts": { 9 | "start": "./mixpanel", 10 | "update": "updtr", 11 | "changelog": "conventional-changelog -i CHANGELOG.md -s -r 0", 12 | "changelog-git": "npm run changelog && git add CHANGELOG.md && git commit -m 'docs(changelog): updated' && git push origin master" 13 | }, 14 | "bin": { 15 | "mixpanel": "./mixpanel" 16 | }, 17 | "main": "mixpanel-cli.js", 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/fgribreau/mixpanel-cli.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/fgribreau/mixpanel-cli/issues" 24 | }, 25 | "homepage": "https://github.com/fgribreau/mixpanel-cli", 26 | "keywords": [ 27 | "mixpanel", 28 | "cli", 29 | "mp", 30 | "import", 31 | "profile" 32 | ], 33 | "devDependencies": { 34 | "conventional-changelog": "^1.1.0", 35 | "conventional-changelog-cli": "^1.2.0", 36 | "updtr": "^0.2.1" 37 | }, 38 | "dependencies": { 39 | "lodash": "^4.16.4", 40 | "mixpanel": "^0.5.0", 41 | "yargs": "^6.3.0" 42 | }, 43 | "license": "MIT" 44 | } 45 | -------------------------------------------------------------------------------- /protocol.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "method": { 4 | "name": "mixpanel.init", 5 | "arguments": [ 6 | { 7 | "name": "token", 8 | "type": "String", 9 | "isRequired": true, 10 | "description": "Your Mixpanel API token" 11 | }, 12 | { 13 | "name": "config", 14 | "type": "Object", 15 | "isRequired": false, 16 | "description": "A dictionary of config options to override" 17 | }, 18 | { 19 | "name": "name", 20 | "type": "String", 21 | "isRequired": false, 22 | "description": "The name for the new mixpanel instance that you want created" 23 | } 24 | ] 25 | }, 26 | "description": "This function initializes a new instance of the Mixpanel tracking object. All new instances are added to the main mixpanel object as sub properties (such as mixpanel.library_name) and also returned by this function. To define a second instance on the page, you would call:mixpanel.init('new token', { your: 'config' }, 'library_name');\nand use it like so:mixpanel.library_name.track(...);\n" 27 | }, 28 | { 29 | "method": { 30 | "name": "mixpanel.push", 31 | "arguments": [ 32 | { 33 | "name": "item", 34 | "type": "Array", 35 | "isRequired": true, 36 | "description": "A [function_name, args...] array to be executed" 37 | } 38 | ] 39 | }, 40 | "description": "push() keeps the standard async-array-push behavior around after the lib is loaded. This is only useful for external integrations that do not wish to rely on our convenience methods (created in the snippet)." 41 | }, 42 | { 43 | "method": { 44 | "name": "mixpanel.disable", 45 | "arguments": [ 46 | { 47 | "name": "events", 48 | "type": "Array", 49 | "isRequired": false, 50 | "description": "An array of event names to disable" 51 | } 52 | ] 53 | }, 54 | "description": "Disable events on the Mixpanel object. If passed no arguments, this function disables tracking of any event. If passed an array of event names, those events will be disabled, but other events will continue to be tracked.Note: this function does not stop other mixpanel functions from firing, such as register() or people.set()." 55 | }, 56 | { 57 | "method": { 58 | "name": "mixpanel.track", 59 | "arguments": [ 60 | { 61 | "name": "event_name", 62 | "type": "String", 63 | "isRequired": true, 64 | "description": "The name of the event. This can be anything the user does - 'Button Click', 'Sign Up', 'Item Purchased', etc." 65 | }, 66 | { 67 | "name": "properties", 68 | "type": "Object", 69 | "isRequired": false, 70 | "description": "A set of properties to include with the event you're sending. These describe the user who did the event or details about the event itself." 71 | }, 72 | { 73 | "name": "callback", 74 | "type": "Function", 75 | "isRequired": false, 76 | "description": "If provided, the callback function will be called after tracking the event." 77 | } 78 | ] 79 | }, 80 | "description": "Track an event. This is the most important and frequently used Mixpanel function." 81 | }, 82 | { 83 | "method": { 84 | "name": "mixpanel.track_links", 85 | "arguments": [ 86 | { 87 | "name": "query", 88 | "type": "Object or String", 89 | "isRequired": true, 90 | "description": "A valid DOM query, element or jQuery-esque list" 91 | }, 92 | { 93 | "name": "event_name", 94 | "type": "String", 95 | "isRequired": true, 96 | "description": "The name of the event to track" 97 | }, 98 | { 99 | "name": "properties", 100 | "type": "Object or Function", 101 | "isRequired": false, 102 | "description": "A properties object or function that returns a dictionary of properties when passed a DOMElement" 103 | } 104 | ] 105 | }, 106 | "description": "Track clicks on a set of document elements. Selector must be a valid query. Elements must exist on the page at the time track_links is called." 107 | }, 108 | { 109 | "method": { 110 | "name": "mixpanel.track_forms", 111 | "arguments": [ 112 | { 113 | "name": "query", 114 | "type": "Object or String", 115 | "isRequired": true, 116 | "description": "A valid DOM query, element or jQuery-esque list" 117 | }, 118 | { 119 | "name": "event_name", 120 | "type": "String", 121 | "isRequired": true, 122 | "description": "The name of the event to track" 123 | }, 124 | { 125 | "name": "properties", 126 | "type": "Object or Function", 127 | "isRequired": false, 128 | "description": "This can be a set of properties, or a function that returns a set of properties after being passed a DOMElement" 129 | } 130 | ] 131 | }, 132 | "description": "Track form submissions. Selector must be a valid query." 133 | }, 134 | { 135 | "method": { 136 | "name": "mixpanel.time_event", 137 | "arguments": [ 138 | { 139 | "name": "event_name", 140 | "type": "String", 141 | "isRequired": true, 142 | "description": "The name of the event." 143 | } 144 | ] 145 | }, 146 | "description": "Time an event by including the time between this call and a later 'track' call for the same event in the properties sent with the event." 147 | }, 148 | { 149 | "method": { 150 | "name": "mixpanel.register", 151 | "arguments": [ 152 | { 153 | "name": "properties", 154 | "type": "Object", 155 | "isRequired": true, 156 | "description": "An associative array of properties to store about the user" 157 | }, 158 | { 159 | "name": "days", 160 | "type": "Number", 161 | "isRequired": false, 162 | "description": "How many days since the user's last visit to store the super properties" 163 | } 164 | ] 165 | }, 166 | "description": "Register a set of super properties, which are included with all events. This will overwrite previous super property values." 167 | }, 168 | { 169 | "method": { 170 | "name": "mixpanel.register_once", 171 | "arguments": [ 172 | { 173 | "name": "properties", 174 | "type": "Object", 175 | "isRequired": true, 176 | "description": "An associative array of properties to store about the user" 177 | }, 178 | { 179 | "name": "default_value", 180 | "type": "*", 181 | "isRequired": false, 182 | "description": "Value to override if already set in super properties (ex: 'False') Default: 'None'" 183 | }, 184 | { 185 | "name": "days", 186 | "type": "Number", 187 | "isRequired": false, 188 | "description": "How many days since the users last visit to store the super properties" 189 | } 190 | ] 191 | }, 192 | "description": "Register a set of super properties only once. This will not overwrite previous super property values, unlike register()." 193 | }, 194 | { 195 | "method": { 196 | "name": "mixpanel.unregister", 197 | "arguments": [ 198 | { 199 | "name": "property", 200 | "type": "String", 201 | "isRequired": true, 202 | "description": "The name of the super property to remove" 203 | } 204 | ] 205 | }, 206 | "description": "Delete a super property stored with the current user." 207 | }, 208 | { 209 | "method": { 210 | "name": "mixpanel.identify", 211 | "arguments": [ 212 | { 213 | "name": "unique_id", 214 | "type": "String", 215 | "isRequired": false, 216 | "description": "A string that uniquely identifies a user. If not provided, the distinct_id currently in the persistent store (cookie or localStorage) will be used." 217 | } 218 | ] 219 | }, 220 | "description": "Identify a user with a unique ID. All subsequent actions caused by this user will be tied to this unique ID. This property is used to track unique visitors. If the method is never called, then unique visitors will be identified by a UUID generated the first time they visit the site." 221 | }, 222 | { 223 | "method": { 224 | "name": "mixpanel.reset", 225 | "arguments": [] 226 | }, 227 | "description": "Clears super properties and generates a new random distinct_id for this instance. Useful for clearing data when a user logs out." 228 | }, 229 | { 230 | "method": { 231 | "name": "mixpanel.get_distinct_id", 232 | "arguments": [] 233 | }, 234 | "description": "Returns the current distinct id of the user. This is either the id automatically generated by the library or the id that has been passed by a call to identify()." 235 | }, 236 | { 237 | "method": { 238 | "name": "mixpanel.alias", 239 | "arguments": [ 240 | { 241 | "name": "alias", 242 | "type": "String", 243 | "isRequired": true, 244 | "description": "A unique identifier that you want to use for this user in the future." 245 | }, 246 | { 247 | "name": "original", 248 | "type": "String", 249 | "isRequired": false, 250 | "description": "The current identifier being used for this user." 251 | } 252 | ] 253 | }, 254 | "description": "Create an alias, which Mixpanel will use to link two distinct_ids going forward (not retroactively). Multiple aliases can map to the same original ID, but not vice-versa. Aliases can also be chained - the following is a valid scenario:mixpanel.alias('new_id', 'existing_id');\n...\nmixpanel.alias('newer_id', 'new_id');\nIf the original ID is not passed in, we will use the current distinct_id - probably the auto-generated GUID." 255 | }, 256 | { 257 | "method": { 258 | "name": "mixpanel.set_config", 259 | "arguments": [ 260 | { 261 | "name": "config", 262 | "type": "Object", 263 | "isRequired": true, 264 | "description": "A dictionary of new configuration values to update" 265 | } 266 | ] 267 | }, 268 | "description": "Update the configuration of a mixpanel library instance.The default config is:{\n // super properties cookie expiration (in days)\n cookie_expiration: 365\n\n // super properties span subdomains\n cross_subdomain_cookie: true\n\n // if this is true, the mixpanel cookie or localStorage entry\n // will be deleted, and no user persistence will take place\n disable_persistence: false\n\n // type of persistent store for super properties (cookie/\n // localStorage) if set to 'localStorage', any existing\n // mixpanel cookie value with the same persistence_name\n // will be transferred to localStorage and deleted\n persistence: 'cookie'\n\n // name for super properties persistent store\n persistence_name: ''\n\n // names of properties/superproperties which should never\n // be sent with track() calls\n property_blacklist: []\n\n // if this is true, mixpanel cookies will be marked as\n // secure, meaning they will only be transmitted over https\n secure_cookie: false\n\n // the amount of time track_links will\n // wait for Mixpanel's servers to respond\n track_links_timeout: 300\n\n // should we track a page view on page load\n track_pageview: true\n\n // if you set upgrade to be true, the library will check for\n // a cookie from our old js library and import super\n // properties from it, then the old cookie is deleted\n // The upgrade config option only works in the initialization,\n // so make sure you set it when you create the library.\n upgrade: false\n}\n" 269 | }, 270 | { 271 | "method": { 272 | "name": "mixpanel.get_config", 273 | "arguments": [] 274 | }, 275 | "description": "returns the current config object for the library." 276 | }, 277 | { 278 | "method": { 279 | "name": "mixpanel.get_property", 280 | "arguments": [ 281 | { 282 | "name": "property_name", 283 | "type": "String", 284 | "isRequired": true, 285 | "description": "The name of the super property you want to retrieve" 286 | } 287 | ] 288 | }, 289 | "description": "Returns the value of the super property named property_name. If no such property is set, get_property() will return the undefined value." 290 | }, 291 | { 292 | "method": { 293 | "name": "mixpanel.people.set", 294 | "arguments": [ 295 | { 296 | "name": "prop", 297 | "type": "Object or String", 298 | "isRequired": true, 299 | "description": "If a string, this is the name of the property. If an object, this is an associative array of names and values." 300 | }, 301 | { 302 | "name": "to", 303 | "type": "*", 304 | "isRequired": false, 305 | "description": "A value to set on the given property name" 306 | }, 307 | { 308 | "name": "callback", 309 | "type": "Function", 310 | "isRequired": false, 311 | "description": "If provided, the callback will be called after the tracking event" 312 | } 313 | ] 314 | }, 315 | "description": "Set properties on a user record." 316 | }, 317 | { 318 | "method": { 319 | "name": "mixpanel.people.set_once", 320 | "arguments": [ 321 | { 322 | "name": "prop", 323 | "type": "Object or String", 324 | "isRequired": true, 325 | "description": "If a string, this is the name of the property. If an object, this is an associative array of names and values." 326 | }, 327 | { 328 | "name": "to", 329 | "type": "*", 330 | "isRequired": false, 331 | "description": "A value to set on the given property name" 332 | }, 333 | { 334 | "name": "callback", 335 | "type": "Function", 336 | "isRequired": false, 337 | "description": "If provided, the callback will be called after the tracking event" 338 | } 339 | ] 340 | }, 341 | "description": "Set properties on a user record, only if they do not yet exist. This will not overwrite previous people property values, unlike people.set()." 342 | }, 343 | { 344 | "method": { 345 | "name": "mixpanel.people.increment", 346 | "arguments": [ 347 | { 348 | "name": "prop", 349 | "type": "Object or String", 350 | "isRequired": true, 351 | "description": "If a string, this is the name of the property. If an object, this is an associative array of names and numeric values." 352 | }, 353 | { 354 | "name": "by", 355 | "type": "Number", 356 | "isRequired": false, 357 | "description": "An amount to increment the given property" 358 | }, 359 | { 360 | "name": "callback", 361 | "type": "Function", 362 | "isRequired": false, 363 | "description": "If provided, the callback will be called after the tracking event" 364 | } 365 | ] 366 | }, 367 | "description": "Increment/decrement numeric people analytics properties." 368 | }, 369 | { 370 | "method": { 371 | "name": "mixpanel.people.append", 372 | "arguments": [ 373 | { 374 | "name": "prop", 375 | "type": "Object or String", 376 | "isRequired": true, 377 | "description": "If a string, this is the name of the property. If an object, this is an associative array of names and values." 378 | }, 379 | { 380 | "name": "value", 381 | "type": "*", 382 | "isRequired": false, 383 | "description": "An item to append to the list" 384 | }, 385 | { 386 | "name": "callback", 387 | "type": "Function", 388 | "isRequired": false, 389 | "description": "If provided, the callback will be called after the tracking event" 390 | } 391 | ] 392 | }, 393 | "description": "Append a value to a list-valued people analytics property." 394 | }, 395 | { 396 | "method": { 397 | "name": "mixpanel.people.union", 398 | "arguments": [ 399 | { 400 | "name": "prop", 401 | "type": "Object or String", 402 | "isRequired": true, 403 | "description": "If a string, this is the name of the property. If an object, this is an associative array of names and values." 404 | }, 405 | { 406 | "name": "value", 407 | "type": "*", 408 | "isRequired": false, 409 | "description": "Value / values to merge with the given property" 410 | }, 411 | { 412 | "name": "callback", 413 | "type": "Function", 414 | "isRequired": false, 415 | "description": "If provided, the callback will be called after the tracking event" 416 | } 417 | ] 418 | }, 419 | "description": "Merge a given list with a list-valued people analytics property, excluding duplicate values." 420 | }, 421 | { 422 | "method": { 423 | "name": "mixpanel.people.track_charge", 424 | "arguments": [ 425 | { 426 | "name": "amount", 427 | "type": "Number", 428 | "isRequired": true, 429 | "description": "The amount of money charged to the current user" 430 | }, 431 | { 432 | "name": "properties", 433 | "type": "Object", 434 | "isRequired": false, 435 | "description": "An associative array of properties associated with the charge" 436 | }, 437 | { 438 | "name": "callback", 439 | "type": "Function", 440 | "isRequired": false, 441 | "description": "If provided, the callback will be called when the server responds" 442 | } 443 | ] 444 | }, 445 | "description": "Record that you have charged the current user a certain amount of money. Charges recorded with track_charge() will appear in the Mixpanel revenue report." 446 | }, 447 | { 448 | "method": { 449 | "name": "mixpanel.people.clear_charges", 450 | "arguments": [ 451 | { 452 | "name": "callback", 453 | "type": "Function", 454 | "isRequired": false, 455 | "description": "If provided, the callback will be called after the tracking event" 456 | } 457 | ] 458 | }, 459 | "description": "Permanently clear all revenue report transactions from the current user's people analytics profile." 460 | }, 461 | { 462 | "method": { 463 | "name": "mixpanel.people.delete_user", 464 | "arguments": [] 465 | }, 466 | "description": "Permanently deletes the current people analytics profile from Mixpanel (using the current distinct_id)." 467 | } 468 | ] 469 | --------------------------------------------------------------------------------