Collecting data with Trackers and Webhooks

  1. Home
  2. Docs
  3. Collecting data with Trackers and Webhooks
  4. Trackers – collecting data from your own applications
  5. Lua Tracker
  6. Tracking specific events

Tracking specific events

Tracking methods supported by the Lua Tracker at a glance:

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


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.

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
Code language: JavaScript (javascript)

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 ) )
Code language: JavaScript (javascript)

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

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 )
Code language: JavaScript (javascript)

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

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 } )
Code language: JavaScript (javascript)

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

Track screen views with trackScreenView()

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

nameHuman-readable name for this screenYesNon-empty string
idUnique identifier for this screenNoString or nil
tstampWhen the screen was viewedNoPositive integer or nil


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

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):

categoryThe grouping of structured events which this action belongs toYesNon-empty string
actionDefines the type of user interaction which this event involvesYesNon-empty string
labelA string to provide additional dimensions to the event dataNoString or nil
propertyA string describing the object or the action performed on itNoString or nil
valueA value to provide numerical data about the eventNoNumber of nil
tstampWhen the structured event occurredNoPositive integer or nil


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

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:

nameThe name of the eventYesNon-empty string
propertiesThe properties of the eventYesNon-empty table
tstampWhen the screen was viewedNoPositive integer or nil


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

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.

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 datatypeDescriptionLua datatypeType suffix(es)Supports array?
NullAbsence of a valueN/ANo
StringString of charactersstringYes
BooleanTrue or falsebooleanYes
IntegerNumber without decimalnumber_INTYes
Floating pointNumber with decimalnumber_FLTYes
Geo-coordinatesLongitude and latitude{ number, number }_GEOYes
DateDate and time (ms precision)number_DT_TM_TMSYes
ArrayArray of values{x, y, z}

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


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


Tracking a String is easy:

{ product_id = "ASO01043" }
Code language: JavaScript (javascript)

Tracking a Boolean is also straightforward:

{ trial = true }
Code language: JavaScript (javascript)

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 = ... }
Code language: JavaScript (javascript)

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.


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 }
Code language: JavaScript (javascript)

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 }
Code language: JavaScript (javascript)

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 } } }
Code language: JavaScript (javascript)