This document covers the necessary steps to migrate from Snowplow to RudderStack and replace your instrumentation code. You can then start using the RudderStack SDKs to track your events with minimal code changes.
Setting up RudderStack dashboard
- Sign up for RudderStack Cloud.
- Set up the source-destination connections in the dashboard to facilitate the event data flow. For more information on setting up the connections, refer to the Quickstart guide.
Updating the SDK implementation
Depending on the platform, follow these steps to move your existing Snowplow SDK implementation to RudderStack:
- Add the following lines of code in your project level
app/build.gradle
file:buildscript {repositories {mavenCentral()}}allprojects {repositories {mavenCentral()}} - Add the following dependency under
dependencies
section in yourapp/build.gradle
file:implementation 'com.rudderstack.android.snowplow:adapter:1.0.0.beta.1' - Update your SDK initialization to any one of the following snippet (method 1, 2, or 3 in the below snippets). Also, replace the
WRITE_KEY
andDATA_PLANE_URL
with your source write key and data plane URL obtained in the above section.//Method 1: Default values are considered for all the configuration objects//except networkConfiguration.RSTracker tracker = new RSTracker().createTracker(this, WRITE_KEY, networkConfiguration);//Method 2: Default values are considered for all the configuration objects.RSTracker tracker = new RSTracker().createTracker(this, WRITE_KEY, DATA_PLANE_URL);//Method 3: Values for all the configuration objects must be provided.RSTracker tracker = new RSTracker().createTracker(this, WRITE_KEY, networkConfiguration,sessionConfiguration, trackerConfiguration,subjectConfiguration);//Method 1: Default values are considered for all the configuration objects//except networkConfiguration.val tracker = RSTracker().createTracker(this, WRITE_KEY, networkConfiguration)//Method 2: Default values are considered for all the configuration objects.val tracker = RSTracker().createTracker(this, WRITE_KEY, DATA_PLANE_URL)//Method 3: Values for all the configuration objects must be provided.val tracker = RSTracker().createTracker(this, WRITE_KEY, networkConfiguration,sessionConfiguration, trackerConfiguration,subjectConfiguration)
Follow the below steps to migrate to the RudderStack iOS SDK:
- Add the SDK to your
Podfile
as shown:pod 'RudderSnowplowMigrator', '1.0.0.beta.1' - Run the following command:pod install
- Add the following code in all the
.m
and.h
files (for Objective-C) or.swift
files(for Swift) where you want to refer or use RudderStack SDK classes:@import RudderSnowplowMigrator;import RudderSnowplowMigrator - Update your SDK initialization to any one of the following snippet (method 1, 2, or 3). Also, replace the
WRITE_KEY
andDATA_PLANE_URL
with your source write key and data plane URL obtained in the above section.//Method 1: Default values are considered for all the configuration objects//except networkConfiguration.RSTracker *tracker = [RSTracker createTrackerWithWriteKey:WRITE_KEY network:networkConfig];//Method 2: Default values are considered for all the configuration objects.RSTracker *tracker = [RSTracker createTrackerWithWriteKey:WRITE_KEY dataPlaneUrl:DATA_PLANE_URL];//Method 3: Values for all the configuration objects must be provided.RSTracker *tracker = [RSTracker createTrackerWithWriteKey:WRITE_KEY network:networkConfig configurations:@[trackerConfig]];//Method 1: Default values are considered for all the configuration objects//except networkConfiguration.let tracker = RSTracker.createTracker(writeKey: WRITE_KEY,network: networkConfig)//Method 2: Default values are considered for all the configuration objects.let tracker = RSTracker.createTracker(writeKey: WRITE_KEY,dataPlaneUrl: DATA_PLANE_URL)//Method 3: Values for all the configuration objects must be provided.let tracker = RSTracker.createTracker(writeKey: WRITE_KEY,network: networkConfig,configurations: [trackerConfig, sessionConfig])
<head>
section of your website. Also, replace the WRITE_KEY
and DATA_PLANE_URL
with your source write key and data plane URL obtained in the above section. <script> rs=window.rs=[],rs.snoplowAdapter=function(){rs.push(Array.prototype.slice.call(arguments))},rs.snoplowAdapter("newTracker",<WRITE_KEY>,<DATA_PLANE_URL>,{<Configurations>}); //Optionally, use RudderStack JavaScript SDK load options rudderanalytics.load();</script>
<script src="https://cdn.rudderlabs.com/adapter/sp/beta/v1/rs-sp-analytics.min.js"></script>
The <Configurations>
parameter in the above snippet can be replaced by the following Snowplow properties which are mapped to the RudderStack properties as shown:
Snowplow property | RudderStack property |
---|---|
cookieDomain | setCookieDomain |
cookieSameSite | sameSiteCookie |
cookieSecure | secureCookie |
Setting the configuration objects for mobile SDKs
RudderStack supports setting values for the following Snowplow configuration objects in the mobile SDKs (iOS/Android). If not set, the default values are assigned.
NetworkConfiguration
The NetworkConfiguration
class can be used to specify the collector endpoint, as shown:
// 1RSNetworkConfiguration *networkConfig = [[RSNetworkConfiguration alloc] initWithDataPlaneUrl:DATA_PLANE_URL];// 2RSNetworkConfiguration *networkConfig = [[RSNetworkConfiguration alloc] initWithDataPlaneUrl:DATA_PLANE_URL controlPlaneUrl:CONTROL_PLANE_URL];
// 1let networkConfig = NetworkConfiguration(dataPlaneUrl: DATA_PLANE_URL)// 2let networkConfig = NetworkConfiguration(dataPlaneUrl: DATA_PLANE_URL, controlPlaneUrl: CONTROL_PLANE_URL)
// 1NetworkConfiguration networkConfiguration = new NetworkConfiguration(DATA_PLANE_URL);// 2NetworkConfiguration networkConfiguration = new NetworkConfiguration(DATA_PLANE_URL, CONTROL_PLANE_URL);
// 1val networkConfiguration = NetworkConfiguration(DATA_PLANE_URL)// 2val networkConfiguration = NetworkConfiguration(DATA_PLANE_URL, CONTROL_PLANE_URL)
dataPlaneUrl
and controlPlaneUrl
are taken as https://hosted.rudderlabs.com
and https://api.rudderlabs.com
respectively.SessionConfiguration
The SessionConfiguration
class can be used to capture sessions to track the user activity in the app, as shown:
RSSessionConfiguration *sessionConfig = [[RSSessionConfiguration alloc] initWithForegroundTimeout:[[NSMeasurement alloc] initWithDoubleValue:30 unit:NSUnitDuration.minutes] backgroundTimeout:[[NSMeasurement alloc] initWithDoubleValue:30 unit:NSUnitDuration.minutes]];
// 2RSSessionConfiguration *sessionConfig = [[RSSessionConfiguration alloc] initWithForegroundTimeoutInSeconds:60 backgroundTimeoutInSeconds:60];
// 1let sessionConfig = SessionConfiguration( foregroundTimeout: Measurement(value: 30, unit: .minutes), backgroundTimeout: Measurement(value: 30, unit: .minutes))
// 2let sessionConfig = SessionConfiguration(foregroundTimeoutInSeconds: 60, backgroundTimeoutInSeconds: 60)
SessionConfiguration sessionConfiguration = new SessionConfiguration( new TimeMeasure(1, TimeUnit.MINUTES), new TimeMeasure(1, TimeUnit.MINUTES));
val sessionConfiguration = SessionConfiguration( TimeMeasure(1, TimeUnit.MINUTES), TimeMeasure(1, TimeUnit.MINUTES));
SessionConfiguration
class as shown in the above code snippets. However, RudderStack ignores the first argument (as it is a dummy argument) and considers only the second argument (backgroundTimeout
).TrackerConfiguration
The TrackerConfiguration
class can be used to configure contexts and automatic events of the tracker and the general behavior, as shown in the below snippets:
RSTrackerConfiguration * trackerConfig = [ [RSTrackerConfiguration alloc] init];[trackerConfig base64Encoding: YES];[trackerConfig logLevel: LogLevelDebug];[trackerConfig sessionContext: YES];[trackerConfig deepLinkContext: YES];[trackerConfig applicationContext: YES];[trackerConfig platformContext: YES];[trackerConfig geoLocationContext: NO];[trackerConfig screenContext: YES];[trackerConfig screenViewAutotracking: YES];[trackerConfig lifecycleAutotracking: YES];[trackerConfig installAutotracking: YES];[trackerConfig exceptionAutotracking: YES];[trackerConfig diagnosticAutotracking: NO];[trackerConfig userAnonymisation: NO];[trackerConfig appId: APP_ID];
let trackerConfig = TrackerConfiguration() .base64Encoding(false) .logLevel(.debug) .deepLinkContext(true) .applicationContext(true) .platformContext(true) .geoLocationContext(true) .lifecycleAutotracking(true) .diagnosticAutotracking(true) .screenViewAutotracking(true) .screenContext(true) .applicationContext(true) .exceptionAutotracking(true) .installAutotracking(true) .userAnonymisation(false) .appId(APP_ID)
TrackerConfiguration trackerConfiguration = new TrackerConfiguration() .base64Encoding(false) .logLevel(LogLevel.VERBOSE) .deepLinkContext(true) .applicationContext(true) .platformContext(true) .geoLocationContext(true) .lifecycleAutotracking(true) .diagnosticAutotracking(true) .screenViewAutotracking(true) .screenContext(true) .applicationContext(true) .exceptionAutotracking(true) .installAutotracking(true) .userAnonymisation(false) .appId(APP_ID);
val trackerConfiguration = TrackerConfiguration() .base64Encoding(false) .logLevel(LogLevel.VERBOSE) .deepLinkContext(true) .applicationContext(true) .platformContext(true) .geoLocationContext(true) .lifecycleAutotracking(true) .diagnosticAutotracking(true) .screenViewAutotracking(true) .screenContext(true) .applicationContext(true) .exceptionAutotracking(true) .installAutotracking(true) .userAnonymisation(false) .appId(APP_ID)
Snowplow automatically captures and tracks the following data. Refer to the Auto-tracked events and entities section for more information.
Variable name | Default value |
---|---|
logLevel | LogLevel.OFF |
lifecycleAutotracking | true |
screenViewAutotracking | true |
sessionContext | true |
SubjectConfiguration
The SubjectConfiguration
class can be used to capture basic user information which is attached to all the events as the context entity.
identify
call if you initialize the SubjectConfiguration
class while initializing the SDK. Note that a user is not identified if the SDK is not initialized.The userId
field is mapped to the RudderStack's userId
. All the other properties are mapped to RudderStack's traits
object.
userId
is a mandatory field. If not provided, the identify
call is ignored.RSSubjectConfiguration * subjectConfig = [ [RSSubjectConfiguration alloc] init];[subjectConfig userId: @ "user_id"];[subjectConfig traits: @ { @ "key_1": @ "value_1", @ "key_2": @20, @ "key_3": @YES}];
let subjectConfig = SubjectConfiguration() .userId("user_id") .traits(["key_1": "value_1", "key_2": 20, "key_3": true])
Traits.Address address = new Traits.Address() .putCity("city value") .putCountry("country value") .putPostalCode("postalCode value") .putState("state value") .putStreet("street value");
Traits.Company company = new Traits.Company() .putName("name value") .putId("id value") .putIndustry("industry value");
Traits traits = new Traits() .putCompany(company) .putAddress(address) .putAge("age value") .putBirthday("birthday value") .putCreatedAt("createAt value") .putDescription("description value") .putEmail("email value") .putFirstName("fName value") .putGender("gender value") .putId("id value") .putLastName("lName value") .putName("name value") .putPhone("phone value") .putTitle("title value") .putUserName("userName value") .put("Key-1", "value-1") .put("Key-2", 20) .put("Key-3", true);
SubjectConfiguration subjectConfiguration = new SubjectConfiguration() .userId("User-1") .traits(traits);
val address: Traits.Address = Traits.Address() .putCity("city value") .putCountry("country value") .putPostalCode("postalCode value") .putState("state value") .putStreet("street value")
val company: Traits.Company = Traits.Company() .putName("name value") .putId("id value") .putIndustry("industry value")
val traits = Traits() .putCompany(company) .putAddress(address) .putAge("age value") .putBirthday("birthday value") .putCreatedAt("createAt value") .putDescription("description value") .putEmail("email value") .putFirstName("fName value") .putGender("gender value") .putId("id value") .putLastName("lName value") .putName("name value") .putPhone("phone value") .putTitle("title value") .putUserName("userName value") .put("Key-1", "value-1") .put("Key-2", 20) .put("Key-3", true)
val subjectConfiguration = SubjectConfiguration() .userId("User-1") .traits(traits)
Updating class names
The below table lists the corresponding class names in Snowplow and RudderStack (mobile SDKs) which need to be updated based on your platform:
Snowplow | RudderStack | |||
---|---|---|---|---|
Java | Kotlin | Objective-C | Swift | |
NetworkConfiguration | NetworkConfiguration | NetworkConfiguration | RSNetworkConfiguration | NetworkConfiguration |
TrackerConfiguration | TrackerConfiguration | TrackerConfiguration | RSTrackerConfiguration | TrackerConfiguration |
SessionConfiguration | SessionConfiguration | SessionConfiguration | RSSessionConfiguration | SessionConfiguration |
SubjectConfiguration | SubjectConfiguration | SubjectConfiguration | RSSubjectConfiguration | SubjectConfiguration |
Structured | Structured | Structured | RSStructured | Structured |
ScreenView | ScreenView | ScreenView | RSScreenView | ScreenView |
Background | Background | Background | RSBackground | Background |
Foreground | Foreground | Foreground | RSForeground | Foreground |
SelfDescribing | SelfDescribing | SelfDescribing | RSSelfDescribing | SelfDescribing |
SelfDescribingJson | SelfDescribingJson | SelfDescribingJson | RSSelfDescribingJson | SelfDescribingJson |
TimeMeasure | TimeMeasure | TimeMeasure | N/A | N/A |
Snowplow | RSTracker | RSTracker | RSTracker | RSTracker |
LogLevel | LogLevel | LogLevel | LogLevel | LogLevel |
Sending event data
You can migrate your existing events from Snowplow to RudderStack by following the below sections:
Identifying a user
SubjectConfiguration
class can be used to identify the users. Refer to the Setting the configuration objects section for more information.Snowplow supports identifying a user by passing the setUserId
method. A Snowplow event including the setUserId
method triggers the identify
call in the RudderStack JavaScript SDK.
setUserId
method of the Snowplow v2 JS tracker.In the below sample call, alex@example.com
is the userId
, while firstName
, lastName
, and city
are the user traits.
rs.snowplowAdapter('setUserId', 'alex@example.com', { firstName: 'Alex', lastName: 'Keener', city: 'New Orleans',});
Tracking user actions
RudderStack SDKs support the following types of Snowplow events:
Custom structured events
RudderStack sends a track call for the Snowplow events containing the Structured
class.
In the below example, RudderStack maps Action_example
to the RudderStack event name and the rest of the properties like Category_example
, label
, value
, etc. to the RudderStack properties.
RSStructured * structured = [ [RSStructured alloc] initWithCategory: @ "Category_example" action: @ "Action_example"];[structured label: @ "my-label"];[structured property: @ "my-property"];[structured value: @5];[structured properties: @ { @ "key_1": @ "value_1", @ "key_2": @ "value_2"}];
[tracker track: structured];
let structured = Structured(category: "Category_example", action: "Action_example") .label("my-label") .property("my-property") .value(5) .properties(["key_1": "value_1", "key_2": "value_2"])
tracker.track(structured)
HashMap < String, Object > properties = new HashMap < > ();properties.put("key-1", "value 1");properties.put("key-2", 123);properties.put("key-3", 123.45);properties.put("key-4", true);properties.put("key-5", false);
Structured structured = new Structured("Category_example", "Action_example") .label("my-label") .value(1234.23) .property("my-property") .properties(properties);
tracker.track(structured);
val properties = mapOf<String, Any>( "key-1" to "value 1", "key-2" to 123, "key-3" to 123.45, "key-4" to true, "key-5" to false)
val structured = Structured("Category_example", "Action_example") .label("my-label") .value(1234.23) .property("my-property") .properties(properties)
tracker.track(structured)
Custom self described events
RudderStack sends a track call for the Snowplow events containing the SelfDescribing
class.
In the below example, RudderStack maps action
to the RudderStack event name.
// 1RSSelfDescribingJson * selfDescribingJson = [ [RSSelfDescribingJson alloc] initWithSchema: @ "schema" andDictionary: @ { @ "action": @ "Action_2", @ "key_2": @ "value_2" }];RSSelfDescribing * selfDescribing = [ [RSSelfDescribing alloc] initWithEventData: selfDescribingJson];
// 2RSSelfDescribing * selfDescribing = [ [RSSelfDescribing alloc] initWithSchema: @ "schema" payload: @ { @ "action": @ "Action_2", @ "key_2": @ "value_2" }];
[tracker track: selfDescribing];
// 1let selfDescribingJson = SelfDescribingJson(schema: "schema", andDictionary: ["action": "Action_2"])let selfDescribing = SelfDescribing(eventData: selfDescribingJson)
// 2let selfDescribing = SelfDescribing(schema: "schema", payload: ["action": "Action_2"])
tracker.track(selfDescribing)
HashMap < String, Object > properties = new HashMap < > ();properties.put("action", "Action-2");properties.put("key-1", "value 1");
// 1SelfDescribingJson selfDescribingJson = new SelfDescribingJson("schema", payload)SelfDescribing selfDescribing = new SelfDescribing(selfDescribingJson)
// 2SelfDescribing selfDescribing = new SelfDescribing("schema", payload)
tracker.track(selfDescribing);
val payload = mapOf < String, Any > ( "action" to "Action-2", "key-2" to "value-2" )
// 1val selfDescribingJson = SelfDescribingJson("schema", payload)val selfDescribing = SelfDescribing(selfDescribingJson)
// 2val selfDescribing = SelfDescribing("schema", payload)
tracker.track(selfDescribing)
action
is a mandatory field. RudderStack does not send any call if it is absent.Custom foreground events
RudderStack sends a track call for the Snowplow events containing the Foreground
class.
RudderStack sends the event name as Application Opened
and maps the rest of the properties like index
, properties
, etc. to the RudderStack properties.
RSForeground * foreground = [ [RSForeground alloc] initWithIndex: @1];[foreground properties: @ { @ "key_1": @ "value_1"}];
[tracker track: foreground];
let foreground = Foreground(index: 1) .properties(["key_1": "value_1"])
tracker.track(foreground)
HashMap < String, Object > properties = new HashMap < > ();properties.put("key-1", "value 1");properties.put("key-2", 123);properties.put("key-3", 123.45);properties.put("key-4", true);properties.put("key-5", false);
Foreground foreground = new Foreground(1234);foreground.setProperties(properties);
tracker.track(foreground);
val properties = mapOf<String, Any>( "key-1" to "value 1", "key-2" to 123, "key-3" to 123.45, "key-4" to true, "key-5" to false)
Foreground foreground = Foreground(1234)foreground.properties = properties
tracker.track(background)
version
, build
, etc. are not present under properties
.Custom background events
RudderStack sends a track call for the Snowplow events containing the Background
class.
RudderStack sends the event name as Application Backgrounded
and maps the rest of the properties, like index
, properties
, etc. to the RudderStack properties.
RSBackground * background = [ [RSBackground alloc] initWithIndex: @1];[background properties: @ { @ "key_1": @ "value_1"}];
[tracker track: background];
let background = Background(index: 1) .properties(["key_1": "value_1"])
tracker.track(background)
HashMap < String, Object > properties = new HashMap < > ();properties.put("key-1", "value 1");properties.put("key-2", 123);properties.put("key-3", 123.45);properties.put("key-4", true);properties.put("key-5", false);
Background background = new Background(1234);background.setProperties(properties);
tracker.track(background);
val properties = mapOf<String, Any>( "key-1" to "value 1", "key-2" to 123, "key-3" to 123.45, "key-4" to true, "key-5" to false)
Background background = Background(1234)background.properties = properties
tracker.track(background)
version
, build
, etc. are not present under properties
.trackStructEvent
and trackSelfDescribingEvent
calls. These Snowplow calls capture user events along with their associated properties and trigger the track
call in the RudderStack JavaScript SDK.A sample
trackSelfDescribingEvent
call is shown below:rs.snowplowAdapter('trackSelfDescribingEvent', { event: { data: { action: 'order completed', category: 'FCW', product_id: 'P1100DFG9766', revenue: 30, currency: 'USD', user_actual_id: 12345, }, },});
trackSelfDescribingEvent
method tracks the Order Completed
event along with other information like revenue
, currency
, and user_actual_id
, etc.A sample
trackStructEvent
call is shown below:rs.snowplowAdapter('trackStructEvent', { action: 'order completed', category: 'FCW', label: 'Sample label', property: 'Some property', value: 40.0,});
trackStructEvent
method tracks the Order Completed
event along with other information like label
, property
, and value
, etc.action
field is mandatory in both the calls.Tracking page or screen views
ScreenView
class captures whenever a new screen is loaded. A Snowplow event including the ScreenView
class triggers the screen call in the RudderStack iOS/Android SDK.RudderStack maps the
name
property to RudderStack event name and the rest of the properties, like screenId
, previousName
, previousId
, etc. to the RudderStack properties.RSScreenView * screen = [ [RSScreenView alloc] initWithName: @ "DemoScreenName" screenId: [ [NSUUID alloc] init ]];[screen type: @ "type"];[screen previousName: @ "previousName"];[screen previousId: @ "previousId"];[screen previousType: @ "previousType"];[screen transitionType: @ "transitionType"];[screen viewControllerClassName: @ "viewControllerClassName"];[screen topViewControllerClassName: @ "topViewControllerClassName"];[screen properties: @ { @ "key_1": @ "value_1", @ "key_2": @ "value_2"}];
[tracker track: screen];
let screen = ScreenView(name: "DemoScreenName", screenId: UUID()) .type("type") .previousName("previousName") .previousId("previousId") .previousType("previousType") .transitionType("transitionType") .viewControllerClassName("viewControllerClassName") .topViewControllerClassName("topViewControllerClassName") .properties: ([ "key_1": "value_1", "key_2": "value_2" ])
tracker.track(screen)
ScreenView screenView = new ScreenView("MainActivity", UUID.randomUUID()) .type("type") .previousName("previousName") .previousId("previousId") .previousType("previousType") .transitionType("transitionType");
tracker.track(screenView);
val screenView = ScreenView("MainActivity", UUID.randomUUID()) .type("type") .previousName("previousName") .previousId("previousId") .previousType("previousType") .transitionType("transitionType")
tracker.track(screenView)
trackPageView
call lets you record your website's page views with any additional relevant information about the viewed page. A Snowplow event including the trackPageView
call triggers the screen call in the RudderStack JavaScript SDK.A sample
trackPageView
call is shown below:rs.snowplowAdapter( 'trackPageView', { title: 'Cart Viewed', }, { path: '/best-seller/1', referrer: 'https://www.google.com/search?q=estore+bestseller', search: 'estore bestseller', title: 'The best sellers offered by EStore', url: 'https://www.estore.com/best-seller/1', },);
Contact us
For more information on the topics covered on this page, email us or start a conversation in our Slack community.