Tracking events
To track an event, pass an Event
instance to the Tracker
.
For example, tracking a ScreenView:
Event event = new ScreenView.builder()
.name("screen name")
.build();
tracker.track(event);
The Java tracker makes it easy to track different kinds of data. We provide a range of Event
classes for tracking out-of-the-box event types as well as fully custom events.
Every tracked event payload has a unique event_id
UUID string. Other ubiquitous properties include the name_tracker
(trackerNamespace
) and app_id
(appId
) set when the Tracker
was initialized. From version 0.12 onwards, Tracker.track()
returns the payload's eventId
.
Snowplow events have a defined structure and protocol that is identical regardless of the tracker used. A minimal payload - the raw event - is sent from the tracker to your collector. The raw event is enriched as it passes through your pipeline. By the time the event arrives in your data storage, depending which enrichments you have enabled, it will have gained different kinds of metadata, and have many more fields than it started with. The default Java tracker event fields are shown here.
The Java tracker Github repository includes a mini demo, "simple-console". The demo sends one event of each type to your event collector.
Auto-tracked events
The Java tracker does not yet support automatic event tracking. All tracking must be implemented manually.
Manually-tracked events summary
The Java tracker provides classes for tracking different types of events. They are listed below.
Event class | e in raw event | eventType in enriched event |
---|---|---|
SelfDescribing (custom) | ue | unstruct |
ScreenView | ue | unstruct |
Timing | ue | unstruct |
PageView | pv | page_view |
Structured | se | struct |
EcommerceTransaction | tr | transaction |
EcommerceTransactionItem | ti | transaction_item |
EcommerceTransaction
/EcommerceTransactionItem
are a legacy design and will be deprecated soon.
SelfDescribing
events (called Unstructured
prior to v1) allow you to track anything that can be described by a JSON schema. The data you provide will be sent as a JSON inside the raw event payload. The specific type of JSON schema needed are described fully on the next page.
The ScreenView
and Timing
out-of-the-box event types are actually wrappers for SelfDescribing
events: the methods for building those events represent fields in their hidden self-describing JSON schemas. This is why both ScreenView
and Timing
events are labelled "unstruct" in the data warehouse.
The PageView
and Structured
event types are processed differently from SelfDescribing
events. Properties tracked using these events are not sent packaged as JSON, but as individual "atomic" fields in the raw event payload. We call these event types "canonical" or "primitive".
SelfDescribing
events and canonical events are loaded into and modelled differently in your data warehouse. The "atomic" fields will always have individual columns.
EcommerceTransaction
and EcommerceTransactionItem
events are legacy primitive events. We recommend instead designing your own SelfDescribing
events plus context entities for eCommerce tracking.
Tracking data that is not event-type specific
Some data, such as that relating to the user whose activity is being tracked, is relevant across all event types. The Java tracker provides two mechanisms for tracking this kind of data.
Certain properties, including userId
or ipAddress
, can be set as "atomic" properties in the raw event, using the Subject
class. Subject
properties relate mainly to client-side tracking. If you are using the Java tracker for server-side tracking, you may wish to pass client-side data for tracking server-side. This is discussed here.
A more general and powerful method is to attach self-describing JSON "context entities" to your events - the same JSON schemas as used for SelfDescribing
events. This means that any data that can be described by a JSON schema can be added to any or all of your events. Read more on the next page.
All events also provide the option for setting a custom timestamp, called trueTimestamp
. See below for details.
Creating a custom event (SelfDescribing)
To track data using an SelfDescribing
event, the data must be structured as a SelfDescribingJson
object, discussed fully on the next page. These require two fields. The first is a URI for a self-describing JSON schema. The second is a data map, and the data must be valid against the schema. SelfDescribing
events can be considered wrappers for sending SelfDescribingJson
.
The simplest initialisation looks like this:
SelfDescribing selfDescribing = SelfDescribing.builder()
.eventData(dataAsSelfDescribingJson)
.build();
See the API docs for the full SelfDescribing.Builder options.
Creating a ScreenView
event
Track screen views with the ScreenView
event. It's a wrapper around a SelfDescribing
event, using this schema.
A simple initialisation looks like this:
ScreenView screenView = ScreenView.builder()
.name("human readable screen name")
.id("unique screen ID")
.build();
At least one of name
or id
must be set. See the API docs for the full ScreenView.Builder options.
Creating a Timing
event
Track how long something took with the Timing
event. It's a wrapper around a SelfDescribing
event, using this schema.
A simple initialisation looks like this:
Timing timing = Timing.builder()
.category("category of the timed event")
.variable("name of the timed event")
.timing(10) // in milliseconds
.label("optional label")
.build();
Provide your timing
value in milliseconds. The label
property is optional. See the API docs for the full Timing.Builder options.
Creating a PageView event
Track page views with the PageView
event. This is a "canonical" event type; data will end up in individual "atomic" columns in the data warehouse.
Property | Field in raw event | Column in enriched event |
---|---|---|
page URL | url | page_url |
page title | page | page_title |
referrer URL | refr | page_referrer |
The provided URLs will also be decomposed into other columns, such as page_urlscheme
, during event enrichment.
A simple initialisation looks like this:
PageView pageViewEvent = PageView.builder()
.pageUrl("https://www.snowplowanalytics.com")
.pagetitle("Snowplow")
.referrer("https://github.com/snowplow/snowplow-java-tracker")
.build();
Only pageUrl
is required. See the API docs for the full PageView.Builder options.
Creating a Structured
event
To track custom data without schemas, use Structured
events. They are the "canonical" equivalent of SelfDescribing
events. The provided data will end up in individual "atomic" columns in the data warehouse. Because of this, it's not possible to fully customise a Structured
event: the fields cannot be renamed, nor new fields added. Structured
events are designed to be similar to Google-style events.
The Structured
event fields have flexible definitions, and what you put into each field is up to you. This is a double-edged sword. It's highly advisable to agree business-wide on definitions for each of these fields, before implementing tracking.
Property | Often contains data about | Field in raw event | Column in enriched event |
---|---|---|---|
category | Grouping for the action | se_ca | se_category |
action | Type of user activity | se_ac | se_action |
label | Additional event data | se_la | se_label |
property | The action or object acted on | se_pr | se_property |
value | Numerical event data | se_va | se_value |
A simple initialisation looks like this:
Structured structured = Structured.builder()
.category("category e.g. auth")
.action("action e.g. logout")
.label("optional label")
.property("optional property")
.value(12.34)
.build();
Both category
and action
are required. See the API docs for the full Structured.Builder options.
Creating EcommerceTransaction
and EcommerceTransactionItem
events
To track eCommerce data, we recommend designing your own schemas for an SelfDescribing
event. We suggest creating one schema for the overall transaction, and another schema for individual items. The transaction schema can be used for the SelfDescribing
event. Items in the transaction can be added as context entities.
The EcommerceTransaction
and EcommerceTransactionItem
events are legacy events, and it's highly likely they will be deprecated in the future. They are designed to be sent together, with one EcommerceTransaction
containing an EcommerceTransactionItem
for every item in the transaction. When the EcommerceTransaction
event is tracked, the EcommerceTransactionItem
events are extracted and sent separately. This means that although you have only tracked one event (using Tracker.track()
), multple events are generated.
EcommerceTransaction
and EcommerceTransactionItem
are "canonical" events. The data will end up in individual "atomic" columns in the data warehouse.
EcommerceTransaction property | Field in raw event | Column in enriched event |
---|---|---|
orderId | tr_id | tr_orderid |
totalValue | tr_tt | tr_total |
affiliation | tr_af | tr_affiliation |
taxValue | tr_tx | tr_tax |
shipping | tr_sh | tr_shipping |
city | tr_ci | tr_city |
state | tr_st | tr_state |
country | tr_co | tr_country |
currency | tr_cu | tr_currency |
EcommerceTransactionItem property | Field in raw event | Column in enriched event |
---|---|---|
itemId | ti_id | ti_orderid |
sku | ti_sk | ti_sku |
price | ti_pr | ti_price |
quantity | ti_qu | ti_quantity |
name | ti_nm | ti_name |
category | ti_ca | ti_category |
currency | ti_cu | ti_currency |
The orderId
and itemId
should be the same, as it's the most direct way to associate the two events once they are in the warehouse.
A simple initialisation looks like this:
// Create events for each item in the transaction
EcommerceTransactionItem item = EcommerceTransactionItem.builder()
.itemId("should be the same as order_id")
.sku("sku")
.price(1.0)
.quantity(2)
.name("item name")
.category("category")
.currency("currency")
.build();
// Then make the EcommerceTransaction event
EcommerceTransaction ecommerceTransaction = EcommerceTransaction.builder()
.items(item) // Add the EcommerceTransactionItem events
.orderId("should be the same as item_id")
.totalValue(2.0)
.affiliation("affiliation")
.taxValue(2.0)
.shipping(3.0)
.city("city")
.state("state")
.country("country")
.currency("currency")
.build();
For EcommerceTransactionItem
events, itemId
, sku
, price
and quantity
are required. For EcommerceTransaction
events, only orderId
and totalValue
are required. See the API docs for the full EcommerceTransaction.Builder and EcommerceTransactionItem.Builder options.
Adding custom timestamps to events
Snowplow events have several timestamps. The raw event payload always contains a deviceCreatedTimestamp
(dtm
) and a deviceSentTimestamp
(stm
). Other timestamps are added as the event moves through the pipeline.
Every Event.Builder
in the Java tracker allows for a custom timestamp, called trueTimestamp
to be set. Read more about timestamps in this still relevant forums post.
A trueTimestamp
can be added to any event using the trueTimestamp()
Builder method:
// This example shows an Unstructured event, but all events can have a trueTimestamp
SelfDescribing selfDescribing = SelfDescribing.builder()
.eventData(dataAsSelfDescribingJson)
.trueTimestamp(1647616394785L)
.build();
trueTimestamp
should be a Long
representing milliseconds since the Unix epoch.