Class: SnowplowTracker::Tracker

Inherits:
Object
  • Object
show all
Defined in:
lib/snowplow-tracker/tracker.rb

Overview

Allows the tracking of events. The tracker accepts event properties to its various track_x_event methods, and creates an appropriate event payload. This payload is passed to one or more Emitters for sending to the event collector.

A Tracker is always associated with one Subject, and one or more Emitter. The Subject object stores information about the user, and will be generated automatically if one is not provided during initialization. It can be swapped out for another Subject using #set_subject.

Tracker objects can access the methods of their associated Subject, e.g. #set_user_id.

The Emitter, or an array of Emitters, must be given during initialization. They will send the prepared events to the event collector. It's possible to add further Emitters to an existing Tracker, using #add_emitter. However, Emitters cannot be removed from Trackers.

At initialization, two Tracker parameters can be set which will be added to all events. The first is the Tracker namespace. This is especially useful to distinguish between events from different Trackers, if more than one is being used. The namespace value will be sent as the tna field in the raw event, mapping to name_tracker in the processed event.

The second user-set Tracker property is the app ID (aid; app_id). This is the unique identifier for the site or application, and is particularly useful for distinguishing between events when Snowplow tracking has been implemented in multiple apps.

The final initialization parameter is a setting for the base64-encoding of any JSONs in the event payload. These will be the SelfDescribingJsons used to provide context to events, or in the #track_self_describing_event method. The default is for JSONs to be encoded. Once the Tracker has been instantiated, it is not possible to change this setting.

Tracking events

The Tracker #track_x_event methods all work similarly. An event payload is created containing the relevant properties, which is passed to an Emitter for sending. All payloads have a unique event ID (event_id) added to them (a type-4 UUID created using the SecureRandom module). This is sent as the eid field in the raw event.

The Ruby tracker provides the ability to track multiple types of events out-of-the-box. The #track_x_event methods range from single purpose methods, such as #track_page_view, to the more complex but flexible #track_self_describing_event, which can be used to track any kind of event. We strongly recommend using #track_self_describing_event for your tracking, as it allows you to design custom event types to match your business requirements.

This table gives the event type in the raw and processed events, defined in the Snowplow Tracker Protocol. This is the e or event parameter. Note that #track_screen_view calls #track_self_describing_event behind the scenes, resulting in a ue event type.


Tracker method e (raw) event (processed)
#track_self_describing_event ue unstruct
#track_struct_event se struct
#track_page_view pv page_view
#track_ecommerce_transaction tr and ti transaction and transaction_item
#track_screen_view ue unstruct


The name ue, "unstructured event", is partially depreciated. This event type was originally created as a counterpart to "structured event", but the name is misleading. An unstruct event requires a schema ruleset and therefore can be considered more structured than a struct event. We prefer the name "self-describing event", after the SelfDescribingJson schema. Changing the event name in the Tracker Protocol would be a breaking change, so for now the self-describing events are still sent as "unstruct".

All the #track_x_event methods share common features and parameters. Every type of event can have an optional context, Subject, and Page added. A Timestamp can also be provided for all event types to override the default event timestamp.

Event context can be provided as an array of SelfDescribingJson. Each element of the array is called an entity. Contextual entities can be used to describe the setting in which the event occurred. For example, a "user" entity could be created and attached to all events from each user. For a search event, entities could be attached for each of the search results. The Ruby tracker does not automatically add any event context. This is in contrast to the Snowplow JavaScript Tracker, which automatically attaches a "webpage" entity to every event that it tracks, containing a unique ID for that loaded page.

Public constants collapse

DEFAULT_ENCODE_BASE64 =

SelfDescribingJson objects are sent encoded by default

true

Instance Method Summary collapse

Constructor Details

#initialize(emitters:, subject: nil, namespace: nil, app_id: nil, encode_base64: DEFAULT_ENCODE_BASE64) ⇒ Tracker

Note:

All the Tracker instance methods return the Tracker object, allowing method chaining, e.g. SnowplowTracker::Tracker.new.set_user_id('12345').track_page_view(page_url: 'www.example.com

Create a new Tracker. emitters is the only strictly required parameter.

Examples:

Initializing a Tracker with all possible options

SnowplowTracker::Tracker.new(
            emitters: SnowplowTracker::Emitter.new(endpoint: 'collector.example.com'),
            subject: SnowplowTracker::Subject.new,
            namespace: 'tracker_no_encode',
            app_id: 'rails_main',
            encode_base64: false
           )

Parameters:

  • emitters (Emitter, Array<Emitter>)

    one or more Emitter objects

  • subject (Subject) (defaults to: nil)

    a Subject object

  • namespace (String) (defaults to: nil)

    a name for the Tracker

  • app_id (String) (defaults to: nil)

    the app ID

  • encode_base64 (Bool) (defaults to: DEFAULT_ENCODE_BASE64)

    whether JSONs will be base64-encoded or not



168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/snowplow-tracker/tracker.rb', line 168

def initialize(emitters:, subject: nil, namespace: nil, app_id: nil, encode_base64: DEFAULT_ENCODE_BASE64)
  @emitters = Array(emitters)
  @subject = if subject.nil?
               Subject.new
             else
               subject
             end
  @settings = {
    'tna' => namespace,
    'tv'  => TRACKER_VERSION,
    'aid' => app_id
  }
  @encode_base64 = encode_base64
end

Instance Method Details

#add_emitter(emitter) ⇒ Object

Add a new Emitter to the internal array of Tracker-associated Emitters.

Parameters:

  • emitter (Emitter)

    an Emitter object



626
627
628
629
# File 'lib/snowplow-tracker/tracker.rb', line 626

def add_emitter(emitter)
  @emitters.push(emitter)
  self
end

#flush(async: false) ⇒ Object

Manually flush all events stored in all Tracker-associated Emitters. By default, this happens synchronously. Emitters can only send events synchronously, while AsyncEmitters can send either synchronously or asynchronously.

Parameters:

  • async (Bool) (defaults to: false)

    whether to flush asynchronously or not



601
602
603
604
605
606
607
# File 'lib/snowplow-tracker/tracker.rb', line 601

def flush(async: false)
  @emitters.each do |emitter|
    emitter.flush(async)
  end

  self
end

#set_color_depth(depth) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_domain_session_id(sid) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_domain_session_idx(vid) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_domain_user_id(duid) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_fingerprint(fingerprint) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_ip_address(ip) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_lang(lang) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_network_user_id(nuid) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_platform(platform) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_screen_resolution(width: , height: ) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_subject(subject) ⇒ Object

Replace the existing Tracker-associated Subject with the provided one. All subsequent events will have the properties of the new Subject, unless they are overriden by event-specific Subject parameters.

Parameters:

  • subject (Subject)

    a Subject object



616
617
618
619
# File 'lib/snowplow-tracker/tracker.rb', line 616

def set_subject(subject)
  @subject = subject
  self
end

#set_timezone(timezone) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_user_id(user_id) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_useragent(useragent) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#set_viewport(width: , height: ) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/snowplow-tracker/tracker.rb', line 211

Subject.instance_methods(false).each do |name|
  if RUBY_VERSION >= '3.0.0'
    define_method name, ->(*args, **kwargs) do
      @subject.method(name.to_sym).call(*args, **kwargs)

      self
    end
  else
    define_method name, ->(*args) do
      @subject.method(name.to_sym).call(*args)

      self
    end
  end
end

#track_ecommerce_transaction(transaction:, items:, context: nil, tstamp: nil, subject: nil, page: nil) ⇒ Object

Track an eCommerce transaction, and all the items in it.

This method is unique in sending multiple events: one transaction event, and one transaction_item event for each item. If Subject or Page objects are provided, their parameters will be merged into both transaction and transaction_item events. The timestamp and event ID of the transaction_item events will always be the same as the transaction. Transaction items are also automatically populated with the order_id and currency fields from the transaction.

Event context is handled differently for transaction and transaction_item events. A context array argument provided to this method will be attached to the transaction event only. To attach a context array to a transaction item, use the key "context" in the item hash.

The transaction and item hash arguments must contain the correct keys, as shown in the tables below.

Transaction fields Description Required? Type
order_id ID of the eCommerce transaction Yes String
total_value Total transaction value Yes Num
affiliation Transaction affiliation No String
tax_value Transaction tax value No Num
shipping Delivery cost charged No Num
city Delivery address city No String
state Delivery address state No String
country Delivery address country No String
currency Transaction currency No String


Item fields Description Required? Type
sku Item SKU Yes String
price Item price Yes Num
quantity Item quantity Yes Integer
name Item name No String
category Item category No String
context Item event context No Array[SelfDescribingJson]

Examples:

Tracking a transaction containing two items

SnowplowTracker::Tracker.new.track_ecommerce_transaction(
  transaction: {
    'order_id' => '12345',
    'total_value' => 49.99,
    'affiliation' => 'my_company',
    'tax_value' => 0,
    'shipping' => 0,
    'city' => 'Phoenix',
    'state' => 'Arizona',
    'country' => 'USA',
    'currency' => 'USD'
  },
  items: [
    {
      'sku' => 'pbz0026',
      'price' => 19.99,
      'quantity' => 1
    },
    {
      'sku' => 'pbz0038',
      'price' => 15,
      'quantity' => 2,
      'name' => 'crystals',
      'category' => 'magic'
    }
  ]
)

Parameters:

  • transaction (Hash)

    the correctly structured transaction hash

  • items (Array<Hash>)

    an array of correctly structured item hashes

  • context (Array<SelfDescribingJson>) (defaults to: nil)

    an array of SelfDescribingJson objects

  • tstamp (DeviceTimestamp, TrueTimestamp, Num) (defaults to: nil)

    override the default DeviceTimestamp of the event

  • subject (Subject) (defaults to: nil)

    event-specific Subject object

  • page (Page) (defaults to: nil)

    event-specific Page object



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/snowplow-tracker/tracker.rb', line 392

def track_ecommerce_transaction(transaction:, items:,
                                context: nil, tstamp: nil,
                                subject: nil, page: nil)
  tstamp = process_tstamp(tstamp)

  transform_keys(transaction)

  payload = Payload.new
  payload.add('e', 'tr')
  payload.add('tr_id', transaction['order_id'])
  payload.add('tr_tt', transaction['total_value'])
  payload.add('tr_af', transaction['affiliation'])
  payload.add('tr_tx', transaction['tax_value'])
  payload.add('tr_sh', transaction['shipping'])
  payload.add('tr_ci', transaction['city'])
  payload.add('tr_st', transaction['state'])
  payload.add('tr_co', transaction['country'])
  payload.add('tr_cu', transaction['currency'])

  finalise_payload(payload, context, tstamp, subject, page)

  track(payload)

  items.each do |item|
    transform_keys(item)
    item['tstamp'] = tstamp
    item['order_id'] = transaction['order_id']
    item['currency'] = transaction['currency']
    track_ecommerce_transaction_item(item, subject, page)
  end

  self
end

#track_page_view(page_url:, page_title: nil, referrer: nil, context: nil, tstamp: nil, subject: nil, page: nil) ⇒ Object

Track a visit to a page.

Examples:

SnowplowTracker::Tracker.new.track_page_view(page_url: 'www.example.com',
                                             page_title: 'example',
                                             referrer: 'www.referrer.com')

Parameters:

  • page_url (String)

    the URL of the page

  • page_title (String) (defaults to: nil)

    the page title

  • referrer (String) (defaults to: nil)

    the URL of the referrer page

  • context (Array<SelfDescribingJson>) (defaults to: nil)

    an array of SelfDescribingJson objects

  • tstamp (DeviceTimestamp, TrueTimestamp, Num) (defaults to: nil)

    override the default DeviceTimestamp of the event

  • subject (Subject) (defaults to: nil)

    event-specific Subject object

  • page (Page) (defaults to: nil)

    override the page_url, page_title, or referrer



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/snowplow-tracker/tracker.rb', line 297

def track_page_view(page_url:, page_title: nil, referrer: nil,
                    context: nil, tstamp: nil, subject: nil, page: nil)
  tstamp = process_tstamp(tstamp)

  payload = Payload.new
  payload.add('e', 'pv')
  payload.add('url', page_url)
  payload.add('page', page_title)
  payload.add('refr', referrer)

  finalise_payload(payload, context, tstamp, subject, page)
  track(payload)

  self
end

#track_screen_view(name: nil, id: nil, context: nil, tstamp: nil, subject: nil, page: nil) ⇒ Object

Track a screen view event. Note that while the name and id parameters are both optional, you must provided at least one of them to create a valid event.

This method creates an unstruct event, by creating a SelfDescribingJson and calling #track_self_describing_event. The schema ID for this is "iglu:com.snowplowanalytics.snowplow/screen_view/jsonschema/1-0-0", and the data field will contain the name and/or ID.

Examples:

SnowplowTracker::Tracker.new.track_screen_view(name: 'HUD > Save Game',
                                               id: 'screen23')

Parameters:

  • name (String) (defaults to: nil)

    the screen name (human readable)

  • id (String) (defaults to: nil)

    the unique screen ID

  • context (Array<SelfDescribingJson>) (defaults to: nil)

    an array of SelfDescribingJson objects

  • tstamp (DeviceTimestamp, TrueTimestamp, Num) (defaults to: nil)

    override the default DeviceTimestamp of the event

  • subject (Subject) (defaults to: nil)

    event-specific Subject object

  • page (Page) (defaults to: nil)

    event-specific Page object

See Also:



528
529
530
531
532
533
534
535
536
537
538
# File 'lib/snowplow-tracker/tracker.rb', line 528

def track_screen_view(name: nil, id: nil, context: nil, tstamp: nil, subject: nil, page: nil)
  screen_view_properties = {}
  screen_view_properties['name'] = name unless name.nil?
  screen_view_properties['id'] = id unless id.nil?

  event_json = SelfDescribingJson.new(SCREEN_VIEW_SCHEMA, screen_view_properties)
  track_unstruct_event(event_json: event_json, context: context,
                       tstamp: tstamp, subject: subject, page: page)

  self
end

#track_self_describing_event(event_json:, context: nil, tstamp: nil, subject: nil, page: nil) ⇒ Object

Track a self-describing event. These are custom events based on SelfDescribingJson, i.e. a JSON schema and a defined set of properties.

This is useful for tracking specific or proprietary event types, or events with unpredicable or frequently changing properties.

This method creates an unstruct event type. It is actually an alias for #track_unstruct_event, which is depreciated due to its unhelpful name.

Examples:

self_desc_json = SnowplowTracker::SelfDescribingJson.new(
  "iglu:com.example_company/save_game/jsonschema/1-0-2",
  {
    "saveId" => "4321",
    "level" => 23,
    "difficultyLevel" => "HARD",
    "dlContent" => true
  }
)

SnowplowTracker::Tracker.new.track_self_describing_event(event_json: self_desc_json)

Parameters:

  • event_json (SelfDescribingJson)

    a SelfDescribingJson object

  • context (Array<SelfDescribingJson>) (defaults to: nil)

    an array of SelfDescribingJson objects

  • tstamp (DeviceTimestamp, TrueTimestamp, Num) (defaults to: nil)

    override the default DeviceTimestamp of the event

  • subject (Subject) (defaults to: nil)

    event-specific Subject object

  • page (Page) (defaults to: nil)

    event-specific Page object



570
571
572
573
# File 'lib/snowplow-tracker/tracker.rb', line 570

def track_self_describing_event(event_json:, context: nil, tstamp: nil, subject: nil, page: nil)
  track_unstruct_event(event_json: event_json, context: context,
                       tstamp: tstamp, subject: subject, page: page)
end

#track_struct_event(category:, action:, label: nil, property: nil, value: nil, context: nil, tstamp: nil, subject: nil, page: nil) ⇒ Object

Track a structured event. category and action are required.

This event type can be used to track many types of user activity, as it is somewhat customizable. This event type is provided particularly for concordance with Google Analytics tracking, where events are structured by "category", "action", "label", and "value".

For fully customizable event tracking, we recommend you use self-describing events.

Examples:

SnowplowTracker::Tracker.new.track_struct_event(
  category: 'shop',
  action: 'add-to-basket',
  property: 'pcs',
  value: 2
)

Parameters:

  • category (String)

    the event category

  • action (String)

    the action performed

  • label (String) (defaults to: nil)

    an event label

  • property (String) (defaults to: nil)

    an event property

  • value (Num) (defaults to: nil)

    a value for the event

  • context (Array<SelfDescribingJson>) (defaults to: nil)

    an array of SelfDescribingJson objects

  • tstamp (DeviceTimestamp, TrueTimestamp, Num) (defaults to: nil)

    override the default DeviceTimestamp of the event

  • subject (Subject) (defaults to: nil)

    event-specific Subject object

  • page (Page) (defaults to: nil)

    event-specific Page object

See Also:



484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/snowplow-tracker/tracker.rb', line 484

def track_struct_event(category:, action:, label: nil, property: nil,
                       value: nil, context: nil, tstamp: nil, subject: nil, page: nil)
  tstamp = process_tstamp(tstamp)

  payload = Payload.new
  payload.add('e', 'se')
  payload.add('se_ca', category)
  payload.add('se_ac', action)
  payload.add('se_la', label)
  payload.add('se_pr', property)
  payload.add('se_va', value)

  finalise_payload(payload, context, tstamp, subject, page)
  track(payload)

  self
end

#track_unstruct_event(event_json:, context: nil, tstamp: nil, subject: nil, page: nil) ⇒ Object

Deprecated.


578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/snowplow-tracker/tracker.rb', line 578

def track_unstruct_event(event_json:, context: nil, tstamp: nil, subject: nil, page: nil)
  tstamp = process_tstamp(tstamp)

  payload = Payload.new
  payload.add('e', 'ue')

  envelope = SelfDescribingJson.new(UNSTRUCT_EVENT_SCHEMA, event_json.to_json)
  payload.add_json(envelope.to_json, @encode_base64, 'ue_px', 'ue_pr')

  finalise_payload(payload, context, tstamp, subject, page)
  track(payload)

  self
end