Skip to content

Lua Tracker

Egor Abramov edited this page Apr 28, 2017 · 5 revisions



1. Overview

The Snowplow Lua Tracker allows you to track Snowplow events from your Lua-based applications, Lua web servers/frameworks, or from the Lua scripting layer within your games or apps.

The tracker should be straightforward to use if you are comfortable with Lua development; any prior experience with Snowplow"s JavaScript Tracker, Google Analytics or Mixpanel (which have similar APIs to Snowplow) is helpful but not necessary.

Note that this tracker has access to a more restricted set of Snowplow events than the JavaScript Tracker.

2 Initialization

Assuming you have completed the Lua Tracker Setup for your Lua project, you are now ready to initialize the Lua Tracker.

2.1 Requiring the module

Require the Lua Tracker"s module into your Lua code like so:

local snowplow = require( "snowplow" )

That's it - you are now ready to initialize a tracker instance.

Back to top

2.2 Creating a tracker

There are two different versions of the tracker constructor, depending on which type of collector you want to log events to.

If you are using a Cloudfront collector, use newTrackerForCf() to initialize your tracker instance. If you are using any other collector (e.g. the Clojure Collector or the Scala Stream Collector), then you should use newTrackerForUri().

2.2.1 Create a tracker logging to Cloudfront with newTrackerForCf()

You can initialize a tracker instance for a Cloudfront collector with:

local t = snowplow.newTrackerForCf( "{{CLOUDFRONT-SUBDOMAIN}}" )

So if your Cloudfront subdomain is d3rkrsqld9gmqf, you would write:

local t = snowplow.newTrackerForCf( "d3rkrsqld9gmqf" )

This completes the initialization of your tracker instance.

Back to top

2.2.2 Create a tracker logging to a non-CloudFront collector using newTrackerForUri()

You can initialize a tracker instance for a non-Cloudfront collector with:

local t = snowplow.newTrackerForUri( "{{COLLECTOR-URI}}" )

So if your collector is available at "", you would write:

local t = snowplow.newTrackerForUri( "" )

This completes the initialization of your tracker instance.

Back to top

2.3 Creating multiple trackers

Each tracker instance is completely sandboxed, so you can create multiple trackers as you see fit.

Here is an example of instantiating two separate trackers:

local t1 = snowplow.newTrackerForCf( "d3rkrsqld9gmqf" )
t1:platform( "cnsl" )
t1:trackUnstructEvent( "save-game", { save_id = 23 }, 1369330092 )

local t2 = snowplow.newTrackerForUri( "" )
t2:platform( "cnsl" )
t2:trackScreenView( "Game HUD", "23" )

t1:trackScreenView( "Test", "23" ) -- Back to first tracker

Back to top

3. Configuration

3.1 Configuring your tracker

Each tracker instance is initialized with sensible defaults:

  • The platform the tracker is running on is set to "pc"
  • Property data for unstructured events is sent Base64-encoded

However you can change either of these defaults:

3.1.1 Change the tracker"s platform with platform()

You can change the platform the tracker is running on by calling:

t:platform( "{{PLATFORM CODE}}" )

For example:

t:platform( "tv" ) -- Running on a Connected TV

For a full list of supported platforms, please see the Snowplow Tracker Protocol.

Back to top

3.1.2 Disable Base64-encoding with encodeBase64()

You can set whether or not to Base64-encode property data for unstructured events by calling:

t:encodeBase64( {{true OR false}} )

So to disable it and send the data URI-encoded instead:

t:encodeBase64( false )

Back to top

3.2 Adding extra data

You may have additional information about your application"s environment, current user and so on, which you want to send to Snowplow with each event.

The tracker instance has a set of set...() methods to attach extra data to all tracked events:

We will discuss each of these in turn below:

3.2.1 Set application ID with setAppId()

You can set the application ID to any string:

t:setAppId( "{{APPLICATION ID}}" )


t:setAppId( "wow-addon-1" )

Back to top

3.2.2 Set user ID with setUserId()

You can set the user ID to any string:

t:setUserId( "{{USER ID}}" )


t:setUserId( "alexd" )

Back to top

3.2.3 Set screen resolution with setScreenResolution()

If your Lua code has access to the device"s screen resolution, then you can pass this in to Snowplow too:

t:setScreenResolution( {{WIDTH}}, {{HEIGHT}} )

Both numbers should be positive integers; note the order is height followed by width. Example:

t:setScreenResolution( 1366, 768 )

Back to top

3.2.4 Set color depth with setColorDepth()

If your Lua code has access to the bit depth of the device"s color palette for displaying images, then you can pass this in to Snowplow too:

t:setColorDepth( {{BITS PER PIXEL}} )

The number should be a positive integer, in bits per pixel. Example:

t:setColorDepth( 32 )

Back to top

4. Tracking specific events

Snowplow has been built to enable you to track a wide range of events that occur when users interact with your websites and apps. We are constantly growing the range of functions available in order to capture that data more richly.

Tracking methods supported by the Lua Tracker at a glance:

Function Description
trackScreenView() Track the user viewing a screen within the application
trackStructEvent() Track a Snowplow custom structured event
trackUnstructEvent() Track a Snowplow custom unstructured event

4.1 Common

All events are tracked with specific methods on the tracker instance, of the form track...(), where XXX is the name of the event to track.

4.1.1 Argument validation

Lua is a dynamically typed language, but each of our track...() methods expects its arguments to be of specific types and value ranges, and validates that to be the case.

If the validation check fails, then a runtime error is thrown:

local t = snowplow.newTrackerForCf( "d3rkrsqld9gmqf" )
local f = function() t:setColorDepth( "unknown" ) end
assert.has_error( f, "depth is required and must be a positive integer, not [unknown]" ) # Busted assertion passes

If your value is of the wrong type, convert it before passing it into the track...() method, for example:

local level_idx = 42
t:trackScreenView( "Game Level", tostring( level_idx ) )

We specify the types and value ranges required for each argument below.

Back to top

4.1.2 Optional timestamp argument

Each track...() method supports an optional timestamp as its final argument; this allows you to manually override the timestamp attached to this event.

If you do not pass this timestamp in as an argument, then the Lua Tracker will use the current time to be the timestamp for the event.

Here is an example tracking a structured event and supplying the optional timestamp argument. Note that we have to explicitly supply nils for the intervening arguments which are empty:

t:trackStructEvent( "hud", "save", nil, nil, nil, 1368725287 )

Timestamp is counted in seconds since the Unix epoch - the same format as generated by os.time() in Lua.

Back to top

4.1.3 Return values

Each track...() method has the same return signature, returning two values:

local status, msg = t:trackUnstructEvent( "save-game", { save_id = "4321", level = 23 } )

These values are as follows:

  1. The first value (status above) is a boolean, set to true if the event was successfully logged to the collector, or false if the event was not successfully logged
  2. The second value (msg above) is a string, which is nil if status is true, but contains the error message if status be false

Back to top

4.2 Track screen views with trackScreenView()

Use trackScreenView() to track a user viewing a screen (or equivalent) within your app. Arguments are:

Argument Description Required? Validation
name Human-readable name for this screen Yes Non-empty string
id Unique identifier for this screen No String or nil
tstamp When the screen was viewed No Positive integer or nil


local s, msg = t:trackScreenView( "HUD > Save Game", "screen23", 1368725287 )

Back to top

4.3 Track structured events with trackStructEvent()

Use trackStructEvent() to track a custom event happening in your app which fits the Google Analytics-style structure of having up to five fields (with only the first two required):

Argument Description Required? Validation
category The grouping of structured events which this action belongs to Yes Non-empty string
action Defines the type of user interaction which this event involves Yes Non-empty string
label A string to provide additional dimensions to the event data No String or nil
property A string describing the object or the action performed on it No String or nil
value A value to provide numerical data about the event No Number of nil
tstamp When the structured event occurred No Positive integer or nil


local s, msg = t:trackStructEvent( "shop", "add-to-basket", nil, "pcs", 2, 1369330909 )

Back to top

4.4 Track unstructured events with trackUnstructEvent()

Use trackUnstructEvent() to track a custom event which consists of a name and an unstructured set of properties. This is useful when:

  • You want to track event types which are proprietary/specific to your business (i.e. not already part of Snowplow), or
  • You want to track events which have unpredictable or frequently changing properties

The arguments are as follows:

Argument Description Required? Validation
name The name of the event Yes Non-empty string
properties The properties of the event Yes Non-empty table
tstamp When the screen was viewed No Positive integer or nil


local s, msg = t:trackUnstructEvent( "save-game", {
                   save_id = "4321",
                   level = 23,
                   difficultyLevel = "HARD",
                   dl_content = true
                 }, 1369330929 )

The properties table consists of a set of individual name = value pairs. The structure must be flat: properties cannot be nested. Be careful here as this is not currently enforced through validation.

Back to top

4.4.1 Supported datatypes

Snowplow unstructured events support a relatively rich set of datatypes. Because these datatypes do not always map directly onto Lua datatypes, we have introduced some "type suffixes" for the Lua property names, so that Snowplow knows what Snowplow data types the Lua data types map onto:

Snowplow datatype Description Lua datatype Type suffix(es) Supports array?
Null Absence of a value N/A - No
String String of characters string - Yes
Boolean True or false boolean - Yes
Integer Number without decimal number _INT Yes
Floating point Number with decimal number _FLT Yes
Geo-coordinates Longitude and latitude { number, number } _GEO Yes
Date Date and time (ms precision) number _DT, _TM, _TMS Yes
Array Array of values {x, y, z} - -

Let"s go through each of these in turn, providing some examples as we go: Null

Tracking a Null value for a given field is currently unsupported in the Lua Tracker. There is a ticket to fix this. String

Tracking a String is easy:

    product_id = "ASO01043"
} Boolean

Tracking a Boolean is also straightforward:

    trial = true
} Integer

To track an Integer, use a Lua number but add a type suffix like so:

    in_stock_INT = 23

Warning: if you do not add the _INT type suffix, Snowplow will assume you are tracking a Floating point number. Floating point

To track a Floating point number, use a Lua number; adding a type suffix is optional:

    price_INT = 4.99,
    sales_tax = 49.99 -- Same as sales_tax_FLT = ...
} Geo-coordinates

Tracking a pair of Geographic coordinates is done like so:

    check_in_GEO = { 40.11041, -88.21337 } -- Lat, long

Please note that the datatype takes the format latitude followed by longitude. That is the same order used by services such as Google Maps.

Warning: if you do not add the _GEO type suffix, then the value will be incorrectly interpreted by Snowplow as an Array of Floating points. Date

Snowplow Dates include the date and the time, with milliseconds precision. There are three type suffixes supported for tracking a Date:

  • _DT - the Number of days since the epoch
  • _TM - the Number of seconds since the epoch
  • _TMS - the Number of milliseconds since the epoch. This precision is hard to access from within Lua

You can track a date by adding a Lua number to your properties object. The following are all valid dates:

    birthday2_DT = 3996,
    registered2_TM = 1371129610,
    last_action_TMS = 1368454114215, -- Accurate to milliseconds

Note that the type prefix only indicates how the Lua number sent to Snowplow is interpreted - all Snowplow Dates are stored to milliseconds precision (whether or not they include that level of precision).

Two warnings:

  1. If you specify a Lua number but do not add a valid Date suffix (_DT, _TM or _TMS), then the value will be incorrectly interpreted by Snowplow as a Number, not a Date
  2. If you specify a Lua number but add the wrong Date suffix, then the Date will be incorrectly interpreted by Snowplow, for example:
    last_ping_DT = 1371129610 -- Should have been _TM. Snowplow will interpret this as the year 3756521449
} Arrays

You can track an Array of values of any data type other than Null.

Arrays must be homogeneous - in other words, all values within the Array must be of the same datatype. This means that the following is not allowed:

    sizes = { "xs", 28, "l", 38, "xxl"] -- NOT allowed

By contrast, the following are all allowed:

    sizes = { "xs", "s", "l", "xl", "xxl" },
    session_starts_TM = { 1371129610, 1064329730, 1341127611 },
    check_ins_GEO = { { -88.21337, 40.11041 }, { -78.81557, 30.22047 } }

Back to top

Clone this wiki locally
You can’t perform that action at this time.