lib/snowplow-tracker/subject.rb
# Copyright (c) 2013-2021 Snowplow Analytics Ltd. All rights reserved.
#
# This program is licensed to you under the Apache License Version 2.0,
# and you may not use this file except in compliance with the Apache License Version 2.0.
# You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the Apache License Version 2.0 is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
# Author:: Snowplow Analytics Ltd
# Copyright:: Copyright (c) 2013-2021 Snowplow Analytics Ltd
# License:: Apache License Version 2.0
module SnowplowTracker
# Subject objects store information about the user associated with the event,
# such as their `user_id`, what type of device they used, or what size screen
# that device had. Also, they store which platform the event occurred on -
# e.g. server-side app, mobile, games console, etc.
#
# Subject parameters are saved into the tracked event as part of the 'atomic'
# event properties, which have their own column in the eventual table of
# events. For example, a Subject's `user_id` parameter will be sent as `uid`
# in the raw event payload, ending up in the `user_id` column. These
# parameters represent part of the [Snowplow Tracker
# Protocol](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol),
# which defines a Snowplow event.
#
# Each {Tracker} is initialized with a Subject. This means that every event by
# default has the platform (`p` parameter in the raw event) `srv`: server-side
# app. Platform is the only preset Subject parameter, which can be overriden
# using the {#set_platform} method. All other parameters must be set manually.
# This can be done directly on the Subject, or, if it is associated with a
# Tracker, via the Tracker, which has access to all the methods of its
# Subject.
#
# Your server-side code may not have access to all these parameters, or they
# might not be useful to you. All the Subject parameters are optional, except
# `platform`.
#
# @example Subject methods can be called from their associated Tracker
# # Creating the components explicitly
# emitter = SnowplowTracker::Emitter.new(endpoint: 'localhost')
# subject = SnowplowTracker::Subject.new
# tracker = SnowplowTracker::Tracker.new(emitters: emitter, subject: subject)
#
# # These lines are equivalent
# subject.set_user_id('12345')
# tracker.set_user_id('12345')
#
# # This would also be equivalent
# emitter = SnowplowTracker::Emitter.new(endpoint: 'localhost')
# subject = SnowplowTracker::Subject.new
# subject.set_user_id('12345')
# tracker = SnowplowTracker::Tracker.new(emitters: emitter, subject: subject)
#
# @example Adding properties to the auto-generated Tracker-associated Subject
# # Creating the components
# emitter = SnowplowTracker::Emitter.new(endpoint: 'localhost')
# tracker = SnowplowTracker::Tracker.new(emitters: emitter)
#
# # Set Subject parameters via the Tracker
# tracker.set_user_id('12345')
#
# Since many of the Subject parameters describe the user, different Subject
# properties may often be desired for each event, if there are multiple users.
# This can be achieved in one of three ways:
#
# 1. the properties of the Tracker-associated Subject can be overriden by the
# properties of an event-specific Subject. A Subject can be added to any
# Tracker `#track_x_event` method call, as one of the arguments. Remember to
# set the platform for the event Subject if you're not using `srv`.
# 2. the Tracker-associated Subject can be swapped for another Subject, using
# the Tracker method {Tracker#set_subject}.
# 3. the properties of the Tracker-associated Subject can be changed before
# every `#track_x_event`, by calling the Subject methods via the Tracker.
#
# @see Tracker#set_subject
# @see
# https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol
# the Snowplow Tracker Protocol
# @see
# https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/ruby-tracker/enriching-your-events/
# the Snowplow docs page about adding context and other extra data to events
# @api public
#
# @note All the Subject instance methods return the Subject object, allowing
# method chaining, e.g.
# `SnowplowTracker::Subject.new.set_timezone('Europe/London').set_user_id('12345')`
class Subject
# @private
DEFAULT_PLATFORM = 'srv'
# @api public
#
# | `p` value | Platform |
# | ---- | ---- |
# | app | General App |
# | cnsl | Games Console |
# | iot | Internet of Things |
# | mob | Mobile/Tablet |
# | pc | Desktop/Laptop/Netbook |
# | srv [DEFAULT] | Server-side App |
# | tv | Connected TV |
# | web | Web (including Mobile Web) |
SUPPORTED_PLATFORMS = %w[app cnsl iot mob pc srv tv web]
# Access the Subject parameters
# @example
# SnowplowTracker::Subject.new.set_user_id('12345').details
# => {"p"=>"srv", "uid"=>"12345"}
# @api public
attr_reader :details
# @api public
def initialize
@details = { 'p' => DEFAULT_PLATFORM }
end
# Set the platform to one of the supported platform values.
# @note Value is sent in the event as `p` (raw event) or `platform` (processed event).
# @see Subject::SUPPORTED_PLATFORMS
# @param [String] platform a valid platform choice
# @example
# subject.set_platform('app')
# @return self
# @api public
def set_platform(platform)
raise "#{platform} is not a supported platform" unless SUPPORTED_PLATFORMS.include?(platform)
@details['p'] = platform
self
end
# Set the unique business-defined user ID for a user.
# @note Value is sent in the event as `uid` (raw event) or `user_id` (processed event).
# For example, an email address.
# @example Example user IDs
# # an email address
# janet.bloggs@email.com
#
# # a username
# janetabloggs2021
#
# @param [String] user_id a unique user ID
# @return self
# @api public
def set_user_id(user_id)
@details['uid'] = user_id
self
end
# Set a business-defined fingerprint for a user.
# @note Value is sent in the event as `fp` (raw event) or `user_fingerprint` (processed event).
# @param [Num] fingerprint a user fingerprint
# @return self
# @example
# subject.set_fingerprint(4048966212)
# @api public
def set_fingerprint(fingerprint)
@details['fp'] = fingerprint
self
end
# Set the device screen resolution.
# @note Value is sent in the event as `res` (raw event) or `dvce_screenheight` and `dvce_screenwidth` (processed event).
# @param [Integer] width the screen width, in pixels (must be a positive integer)
# @param [Integer] height the screen height, in pixels (must be a positive integer)
# @return self
# @example
# subject.set_screen_resolution(width: 2880, height: 1800)
# @api public
def set_screen_resolution(width:, height:)
@details['res'] = "#{width}x#{height}"
self
end
# Set the dimensions of the current viewport.
# @note Value is sent in the event as `vp` (raw event) or `br_viewwidth` and `br_viewheight` (processed event).
# @param [Integer] width the viewport width, in pixels (must be a positive integer)
# @param [Integer] height the viewport height, in pixels (must be a positive integer)
# @return self
# @example
# subject.set_viewport(width: 1440, height: 762)
# @api public
def set_viewport(width:, height:)
@details['vp'] = "#{width}x#{height}"
self
end
# Set the color depth of the browser, in bits per pixel.
# @note Value is sent in the event as `cd` (raw event) or `br_colordepth` (processed event).
# @param [Num] depth the colour depth
# @example
# subject.set_color_depth(24)
# @return self
# @api public
def set_color_depth(depth)
@details['cd'] = depth
self
end
# Set the timezone to that of the user's OS.
# @note Value is sent in the event as `tz` (raw event) or `os_timezone` (processed event).
# @example
# subject.set_timezone('Africa/Lagos')
# @param [String] timezone the timezone
# @return self
# @api public
def set_timezone(timezone)
@details['tz'] = timezone
self
end
# Set the language.
# @note Value is sent in the event as `lang` (raw event) or `br_lang` (processed event).
# @example Setting the language to Spanish
# subject.set_lang('es')
# @param [String] lang the language being used on the device
# @return self
# @api public
def set_lang(lang)
@details['lang'] = lang
self
end
# Set the domain user ID.
# @note Value is sent in the event as `duid` (raw event) or `domain_userid` (processed event).
# @see Subject#set_network_user_id
# @see Subject#set_domain_session_id
# @see Subject#set_domain_session_idx
# @see https://github.com/simplybusiness/snowplow_ruby_duid/ snowplow_ruby_duid, a third party gem
# @see https://github.com/snowplow-incubator/snowplow-ruby-tracker-examples
# Ruby tracker example Rails app
# @example
# subject.set_domain_user_id('aeb1691c5a0ee5a6')
# @param [String] duid the unique domain user ID
# @return self
# @api public
#
# The `domain_userid` is a client-side unique user ID, which is set by the
# browser-based JavaScript tracker, and stored in a first party cookie
# (cookie name: `_sp_id`). For stitching together client-side and
# server-side events originating from the same user, the domain user ID can
# be extracted from the cookie and set using this method. A third party gem,
# [snowplow_ruby_duid](https://github.com/simplybusiness/snowplow_ruby_duid/),
# has been created to help with this.
#
# @example Ruby on Rails: getting the domain_user_id from the cookie
# # Assuming the Snowplow JavaScript has also been incorporated
# # cookies are accessible only within a Controller
# def snowplow_domain_userid
# sp_cookie = cookies.find { |key, _value| key =~ /^_sp_id/ }
# sp_cookie.last.split(".").first if sp_cookie.present?
# end
#
def set_domain_user_id(duid)
@details['duid'] = duid
self
end
# Set the domain session ID.
# @note Value is sent in the event as `sid` (raw event) or `domain_sessionid` (processed event).
# @see Subject#set_network_user_id
# @see Subject#set_domain_user_id
# @see Subject#set_domain_session_idx
# @example
# subject.set_domain_session_id('9c65e7f3-8e8e-470d-b243-910b5b300da0')
# @param [String] sid the unique domain session ID
# @return self
# @api public
#
# The `domain_sessionid` is a client-side unique ID for a user's current
# session. It is set by the browser-based JavaScript trackers, and stored in
# a first party cookie (cookie name: `_sp_id`), along with other parameters
# such as `domain_userid`. For stitching together client-side and
# server-side events originating from the same user and session, the domain
# session ID can be extracted from the cookie and set using this method.
def set_domain_session_id(sid)
@details['sid'] = sid
self
end
# Set the domain session index.
# @note Value is sent in the event as `vid` (raw event) or `domain_sessionidx` (processed event).
# @see Subject#set_network_user_id
# @see Subject#set_domain_user_id
# @see Subject#set_domain_session_id
# @example
# subject.set_domain_session_idx(3)
# @param [Num] vid the number of sessions
# @return self
# @api public
#
# The `domain_sessionidx` is a client-side property that records how many
# visits (unique `domain_sessionid`s) a user (a unique `domain_userid`) has
# made to the site. It is stored in the first party cookie set by the
# JavaScript tracker, along with other parameters such as `domain_userid`.
# For stitching together client-side and server-side events originating from
# the same user and session, the domain session index can be extracted from
# the cookie and set using this method.
def set_domain_session_idx(vid)
@details['vid'] = vid
self
end
# Set the user's IP address.
# @note Value is sent in the event as `ip` (raw event) or `user_ipaddress` (processed event).
# @param [String] ip the IP address
# @return self
# @example
# subject.set_ip_address('37.157.33.178')
# @api public
def set_ip_address(ip)
@details['ip'] = ip
self
end
# Set the browser user agent.
# @note Value is sent in the event as `ua` (raw event) or `useragent` (processed event).
# @example
# subject.set_useragent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:92.0) Gecko/20100101 Firefox/92.0')
# @param [String] useragent the user agent string
# @return self
# @api public
def set_useragent(useragent)
@details['ua'] = useragent
self
end
# Set the network user ID.
# @note Value is sent in the event as `tnuid` (raw event) and `network_userid` (processed event).
# @see Subject#set_domain_user_id
#
# The network user ID is, like the `domain_userid`, a cookie-based unique
# user ID. It is stored in a third party cookie set by the event collector,
# hence the name "network" as it is set at a network level. It is the
# server-side user identifier. The raw event does not contain a `nuid`
# value; the `network_userid` property is added when the event is processed.
#
# The default behaviour is for the collector to provide a new cookie/network
# user ID for each event it receives. This method provides the ability to
# override the collector cookie's value with your own generated ID.
#
# Domain user IDs set on the Subject in this way are sent as `tnuid` in the
# raw event.
#
# @example
# subject.set_network_user_id('ecdff4d0-9175-40ac-a8bb-325c49733607')
# @param [String] nuid the network user ID
# @return self
# @api public
def set_network_user_id(nuid)
@details['tnuid'] = nuid
self
end
end
end