Snowplow Python Tracker 0.3.0 released


We are pleased to announce the release of the Snowplow Python Tracker version 0.3.0. In this version we have added support for Snowplow custom contexts for all events. We have also updated the API for tracker initialization and ecommerce transaction tracking, added the option to turn off Pycontracts to improve performance, and added an event vendor parameter for custom unstructured events.

In the rest of the post we will cover:

  1. Tracker initialization
  2. Disabling contracts
  3. Ecommerce tracking
  4. Custom contexts
  5. Event vendors
  6. Context vendors
  7. Tracking method return values
  8. Other improvements
  9. Upgrading
  10. Support

1. Tracker initialization

Several optional configuration arguments have been added to the Tracker class’s initialization function. Its new signature looks like this:

def __init__(self, collector_uri, namespace=None, app_id=None, context_vendor=None, encode_base64=True, contracts=True):

The example below would initialize a tracker whose name is “cf” for an application whose ID is “ae9f587d23”. It would disable Pycontracts. It does not change the default behaviour of Base64-encoding event data.

from snowplow_tracker.tracker import Tracker t = Tracker("", "cf", "ae9f587d23", "com.example", False)

2. Disabling contracts

The Python Tracker uses the Pycontracts module for type checking, so a runtime error will be raised if you pass a method a parameter of the wrong type. This check does introduce a performance hit, so we have added the option to disable Pycontracts when configuring a tracker by setting the contracts argument to False:

from snowplow_tracker.tracker import Tracker t = Tracker("", contracts=False)

3. Ecommerce tracking

In previous versions of the Python Tracker, you had to individually call a tracking method for each item in the ecommerce transaction and for the transaction as a whole. The new version has a single method called track_ecommerce_transaction that is called once per transaction. This is its signature:

def track_ecommerce_transaction(self, order_id, total_value, affiliation=None, tax_value=None, shipping=None, city=None, state=None, country=None, currency=None, items={}, context=None, tstamp=None):

The required fields are order_id, total_value, and items.

The relevant argument here is items. This should be an array, each of whose entries is a dictionary containing data about a single item in the transaction. The mandatory fields in the dictionary are sku, price, and quantity.

An example may help. The call to track an ecommerce transaction in which two items are sold might look like this:

t.track_ecommerce_transaction("6a8078be", 45, city="London", currency="GBP", items= [{ "sku": "pbz0026", "price": 20, "quantity": 1, "name": "crystal ball" }, { "sku": "pbz0038", "price": 15, "quantity":
 1, "name": "tarot deck" }])

This will fire three events: one for each transaction item and one for the transaction as a whole. The order_id and currency fields will be attached to all three events; the total_value and city fields will only be attached to the transaction event, not the transaction item events.

The three events are guaranteed to have the same dtm and tid fields, where dtm is the timestamp and tid is a random 6-digit transaction ID attached to every Snowplow event.

For more detailed documentation, including a full list of fields available for each item in the transaction, see the wiki.

4. Custom contexts

In short, custom contexts let you add additional information about the circumstances surrounding an event in the form of a Python dictionary object. Each tracking method now accepts an additional optional contexts parameter before the optional timestamp parameter:

def track_page_view(self, page_url, page_title=None, referrer=None, context=None, tstamp=None):

The context argument is a Python dictionary. Each of its keys is the name of a context, and each of its values is the flat (not nested) dictionary for that context. So if a visitor arrives on a page advertising a movie, the context argument might look like this:

{ "movie_poster": { # Context entry  "movie_name": "Solaris", "poster_country": "JP", "poster_year$dt": new Date(1978, 1, 1) } }

This is how to fire a page view event with the above custom context:

t.track_page_view("", "Homepage", context={ "movie_poster": { "movie_name": "Solaris", "poster_country": "JP", "poster_year$dt": new Date(1978, 1, 1) } })

In order to avoid confusion between custom contexts defined by different companies, fill in the context_vendor argument when initializing a tracker:

from snowplow_tracker.tracker import Tracker t = Tracker("", context_vendor="com.example")

Then whenever the tracker fires an event with a custom context, the event will include the context vendor you provide.

The context vendor string should contain no characters other than lowercase letters, underscores, and dots. It should be your company’s reversed Internet domain name – for example, “” for contexts developed at the company with domain name “”.

For more on custom contexts, see the blog post which introduced them in the Snowplow JavaScript Tracker.

5. Event vendors

The event vendor parameter represents the company who developed the model for an event. It is analogous to the context vendor parameter, although it is not part of tracker construction. All events other than custom unstructured events have “com.snowplowanalytics” automatically set in their event vendor field.

Custom unstructured events now have a mandatory event_vendor initial field:

def track_unstruct_event(self, event_vendor, event_name, dict_, context=None, tstamp=None):

Use it like this:

t.track_unstruct_event("com.your_company", "viewed_product", { "product_id": "ASO01043", "price": 49.95 })

The event vendor string should follow the same rules as the context vendor string.

6. Tracking method return values

Each tracking method now returns a tuple based on the status code of the request it fired. If the code is between 0 and 400, it returns a tuple whose first element is true and whose second is the code:

(true, 200)

If the code is a number not in that range, the first element is instead false:

(false, 500)

Finally, if the host is not found:

(false, "Host [] not found (possible connectivity error")

7. Other improvements

We have also:

  • Added classifiers to #48
  • Added a coveralls code coverage button to the README #63

8. Upgrading

The release version of this tracker (0.3.0) is available on PyPI, the Python Package Index repository, as snowplow-tracker. Download and install it with pip:

$ pip install snowplow-tracker --upgrade

Or with setuptools:

$ easy_install -U snowplow-tracker

For more information on getting started with the Snowplow Python Tracker, see the setup page.

9. Support

Please get in touch if you need help setting up the Snowplow Python Tracker or want to suggest a new feature. The Snowplow Python Tracker is still young, so of course do raise an issue if you find any bugs.