Solved

filter_by_cohort in Python

  • 14 January 2020
  • 1 reply
  • 226 views

Hello, 

I’m attempting to create a JSON file of user emails based on cohort. I’ve attempted two separate solutions. First, I tried simply building a POST request to the engage endpoint (here’s a simplified version):

endpointURL=#API KEY:@mixpanel.com/api/2.0/engage
cohort_id=12345
queryParams={'filter_by_cohort':{"id":cohort_id}, 'output_properties':["$email"]}
response=requests.post(url=endpointURL, params=queryParams)

The problem is, this encodes the special characters, so when I send the request it fails with “error: “invalid parameter: filter_by_cohort””. When I manually build the request in Postman, it works, but the percent escape characters break the request when I build it in my script. 

My alternative solution was trying to use the mixpanel_api feeding in the same query parameters, but it similarly fails with an Invalid parameter error. 

Is there another potential solution? Or, are there at least potential updates that allow the API to handle encoded URLs? 

Thanks!

icon

Best answer by raja 14 January 2020, 23:13

It seems the params encoding method in the requests library is not handling dicts encoding in the way the Engage API expects, for example:

queryParams={'filter_by_cohort':{"id":1}, 'output_properties':["$email"]}
r = requests.post('https://httpbin.org/post', params=queryParams)
r.url
# u'https://httpbin.org/post?output_properties=%24email&filter_by_cohort=id'

In the example above you can see that the filter_by_cohort value was mangled after the encoding done by requests.post.

Solution:

We can see that the Mixpanel API code has a custom encoding method, using that method gives us this output using the example above:

r = requests.post('https://httpbin.org/post?' + _unicode_urlencode(queryParams))
r.url
# u'https://httpbin.org/post?output_properties=%5B%22%24email%22%5D&filter_by_cohort=%7B%27id%27%3A+1%7D'

We can extract that encoding method and make a custom encoding method to include with your script -- something along the lines of:

import urllib
import json
def _unicode_urlencode(params):
if isinstance(params, dict):
params = params.items()
for i, param in enumerate(params):
if isinstance(param[1], list):
params[i] = (param[0], json.dumps(param[1]),)
result = urllib.urlencode([(k, isinstance(v, unicode) and v.encode('utf-8') or v) for k, v in params])
return result

endpointURL = "<API KEY>:@mixpanel.com/api/2.0/engage"
cohort_id = 12345
queryParams = {'filter_by_cohort': {"id": cohort_id}, 'output_properties': ["$email"]}
response = requests.post(url=endpointURL + '?' + _unicode_urlencode(queryParams))

 

View original

1 reply

Userlevel 1
Badge

It seems the params encoding method in the requests library is not handling dicts encoding in the way the Engage API expects, for example:

queryParams={'filter_by_cohort':{"id":1}, 'output_properties':["$email"]}
r = requests.post('https://httpbin.org/post', params=queryParams)
r.url
# u'https://httpbin.org/post?output_properties=%24email&filter_by_cohort=id'

In the example above you can see that the filter_by_cohort value was mangled after the encoding done by requests.post.

Solution:

We can see that the Mixpanel API code has a custom encoding method, using that method gives us this output using the example above:

r = requests.post('https://httpbin.org/post?' + _unicode_urlencode(queryParams))
r.url
# u'https://httpbin.org/post?output_properties=%5B%22%24email%22%5D&filter_by_cohort=%7B%27id%27%3A+1%7D'

We can extract that encoding method and make a custom encoding method to include with your script -- something along the lines of:

import urllib
import json
def _unicode_urlencode(params):
if isinstance(params, dict):
params = params.items()
for i, param in enumerate(params):
if isinstance(param[1], list):
params[i] = (param[0], json.dumps(param[1]),)
result = urllib.urlencode([(k, isinstance(v, unicode) and v.encode('utf-8') or v) for k, v in params])
return result

endpointURL = "<API KEY>:@mixpanel.com/api/2.0/engage"
cohort_id = 12345
queryParams = {'filter_by_cohort': {"id": cohort_id}, 'output_properties': ["$email"]}
response = requests.post(url=endpointURL + '?' + _unicode_urlencode(queryParams))

 

Reply