@divegames/dive-ts-mobile-sdk
Dive Analytics React Native Typescript SDK 2.0
Our SDK is written entirely in TypeScript. It has no native code of its own: device features (persistent storage, device model, advertising id) come from a few well-known React Native libraries that you install alongside it. It works in Expo projects (development builds / EAS, not Expo Go) and in bare React Native projects.
Compatibility
| Requirement | Version |
|---|---|
| React Native | 0.76 or newer (New Architecture). Tested on 0.86 |
| Expo SDK | 52 or newer. Tested on SDK 57 |
| TypeScript (consumer) | 5.x |
@react-native-async-storage/async-storage |
2.x |
react-native-device-info |
15.x |
expo-tracking-transparency |
5.x or newer (57.x on Expo SDK 57) |
Upgrading from 1.5? See Migrating from 1.5.
Quick Start
Expo projects
npx expo install @divegames/dive-ts-mobile-sdk
npx expo install @react-native-async-storage/async-storage react-native-device-info expo-tracking-transparency
Add the tracking-transparency plugin to app.json so the iOS permission text is generated for you:
{
"expo": {
"plugins": [
[
"expo-tracking-transparency",
{ "userTrackingPermission": "This identifier will be used to deliver personalized ads to you." }
]
]
}
}
Then rebuild the native project (npx expo prebuild + npx expo run:ios / run:android, or an EAS build). The SDK cannot run inside Expo Go because react-native-device-info and expo-tracking-transparency include native code.
Bare React Native projects
- Install the Expo modules runtime once (this does not turn your app into an Expo app, it only enables Expo packages):
npx install-expo-modules@latest - Install the SDK and its peers:
npm install --save @divegames/dive-ts-mobile-sdk @react-native-async-storage/async-storage react-native-device-info expo-tracking-transparency npx pod-install - iOS: add
NSUserTrackingUsageDescriptiontoios/<App>/Info.plist. - Android:
expo-tracking-transparencyalready declarescom.google.android.gms.permission.AD_IDin its manifest; nothing to add.
Import
import { DiveSDK, EventBody } from '@divegames/dive-ts-mobile-sdk';
Then call DiveSDK.Init(DiveConfig) with the configuration provided by the Dive Team.
Init the SDK
The method DiveSDK.Init(DiveConfig) initializes the SDK and sends the sdkStarted event.
- Call this method as early as possible and only once
- Create a new
DiveConfigand fill the following parameters
DiveConfig
The Dive Team will provide all configuration elements:
AppToken- This is is the key that was generated for your game (UUID)HashKey- Secret key used to hash the body of the events for consistency check with the serverAnalyticsURL- This is the custom URL of your event server. This can also be updated remotely via Remote SettingsEnvironment- To properly test the events, use theDEVenvironment. If you are uploading the build to the stores usePRODenvironment.HasIdentityConsent- This defines how we track the player. If it is set to false all data is
anonymous and the SDK never asks for the tracking permission. Default Value: True.
ShowLogs- This enables or disables the debug logs. Warnings and errors are always shown.
Default Value: True.
GameVersion- Config Game Version is required in the initApiURL- This is the custom URL for the API server, for now it is used for Remote Config (developer server). This can also be updated remotely via Remote Settings.
Init example
import { DiveSDK } from "@divegames/dive-ts-mobile-sdk";
DiveSDK.Init({
AppToken: "119bbf52-2248-416b-921d-16178847d121",
HashKey: "EBmKgrWfrdfkerTt4mPs6Fxgs3Nv4kSQgjhgrUuRDcdUEr24wj",
AnalyticsURL: "https://public.dive.games/fallback-events",
ApiURL: "https://apitest.dive.games",
Environment: "DEV",
HasIdentityConsent: true,
ShowLogs: true,
GameVersion: "1.0"
});
Device identity (IDFA / GAID)
When HasIdentityConsent is true the SDK asks for the App Tracking Transparency permission on iOS (Android needs no prompt) and reports the advertising identifier in the deviceInfo event as id_type: "IDFA" / "GAID". If the user declines, the identifier is restricted, or Android returns the all-zero id, the device is tracked as id_type: "anonymous".
Restarting a session Manually
If you need to restart or renew an active player session, call DiveSDK.Init(DiveConfig); again.
- This cleans all the data from the previous session including,
Custom Player Config,Started Checkpointsand other session data. - You need to perform the same Init sequence again (see
Example Sequencebelow ) - The SDK automatically adds a
c_session_restarted_fromglobal header with the previousc_session_id
Custom Player Config
Depending on your game, there are some configurations that MUST be set before launching the DiveSDK.Launch();
DiveSDK.getInstance().SetPlayerId(playerID:string); - This sets the ID you use to track the player.DiveSDK.getInstance().SetServerSessionId(sessionID:string); - If your game has a custom server session id.DiveSDK.getInstance().SetPlayerLevel(currentLevel:number);- This has to be setup on every startup and when the player levels up.DiveSDK.getInstance().SetPlayerXp(currentXp:number);- This has to be setup on every startup and when the player gains xp.DiveSDK.getInstance().SetDiveCid(cid:string);- This sets the Dive campaign id. This will override the one detected in deep link.
Note: DiveSDK class accepts method chaining. So, it's possible to write all the configuration in a single line, as shown below:
import { DiveSDK } from "@divegames/dive-ts-mobile-sdk";
//1. Init the SDK using DiveConfig
//2. Set the Custom Player Config
DiveSDK
.getInstance()
.SetPlayerId("1b314049-b9e8-4650-90ec-071f34d137ac")
.SetServerSessionId("98e6e003-b4c2-4ac6-9176-0350cafb8108")
.SetPlayerLevel(10)
.SetPlayerXp(9400)
.SetDiveCid("22");
//3. Trigger the launch with or without parameters
DiveSDK.getInstance().Launch();
Launch the SDK
The method DiveSDK.getInstance().Launch(); sends the appLaunched event.
- Call it as soon as you have all the information required.
- This method automatically adds device information parameters to the event body .
- Only call this event once in the player session.
- The Dive Team might request some custom parameters to be passed to the Launch event.
Example without custom parameters:
DiveSDK.getInstance().Launch();
Example with custom parameters:
DiveSDK.getInstance()
.Launch(
new EventBody()
.AddParam("c_id", 1903839193)
.AddParam("is_refreshed", false)
.AddParam("extra_raw_params", "json string")
);
Record Events
You can easily record custom events by using DiveSDK.getInstance().RecordEvent method and the EventBody class.
- Set the name of the event as string .
- Create a new
EventBody() class. - Call
AddParam(string,object)to add custom event parameters to the event.
For example:
DiveSDK.getInstance()
.RecordEvent("userLoggedIn", new EventBody()
.AddParam("login_type", "guest")
.AddParam("coins", 2000)
.AddParam("gems", 120)
);
Important: The EventBody class support adding any object type. Avoid sending entire data class objects with nested elements, consider using a JSON string and check with the Dive Team for special cases.
Set the Logger with ShowLogs in the DiveSDK to debug the current data being sent to the server. Your data will appear in the "body":{ } the other elements are automatically added by the sdk.
Raw JSON sent:
{
"name": "userLoggedIn",
"level_before": 3,
"xp_before": 94000,
"player_id": "34223465454",
"s_session_id": "b98d5fbe-80b0-417d-837c-11a23ab4ad32",
"game_ver": "1.0",
"app_token": "cc326318-7783-404f-83e5-7220bb34b960",
"platform": "ios",
"env": "DEV",
"device_id": "c51348fb-8002-48ab-933e-9a20c1ef6e7f",
"c_session_id": "b26b2fac-4920-45cf-b1de-edf74564cb37",
"uuid": "2ad8c235-6541-41c2-b6cc-fbdb6a3896b6",
"timezone": "-0300",
"ts": "2020-07-27T16:54:06Z",
"timestamp_utc": "2020-07-27T19:54:06Z",
"unixts": 1595879646,
"sdk_ver": "RN Dive SDK 2.0.0",
"body": {
"login_type": "guest",
"coins": 2000,
"gems": 120
}
}
ScreenViewed Event:
To properly track the user screen flow, call the DiveSDK.getInstance().ScreenViewed method as soon as you display the Screen to the player. (example: lobby, menu, store, etc.)
- Call the method every time you show the screen.
- Set the screen name as
stringparameter. - The Dive Team will provide a list of relevant screens to track.
DiveSDK.getInstance().ScreenViewed("store");
The SDK will automatically remember the last screen viewed and send the correct screenViewed event
Error Event:
To create a errorCreated event call the DiveSDK.getInstance().RecordError method. This is commonly used when you have unexpected situations in your game. (example: The store receipt validation failed, your user logged out or similar)
- Every error reported must have a error code as
string - To put the error in context add a description as
string
DiveSDK.getInstance().RecordError("401", "Failed to validate Store Receipt. Invalid Token.");
Checkpoints Time Tracking:
Checkpoints are used to measure periods of time in your game (example: asset loading, server calls, boot sequence or similar).
- To
STARTa checkpoint callDiveSDK.getInstance().StartCheckpoint(string)and pass the checkpoint name asstring. - To
ENDa checkpoint callDiveSDK.getInstance().EndCheckpoint(string)and pass the original checkpoint name asstring. - Checkpoints names are unique, this means you have to end a checkpoint before starting a new one with the same name.
- If needed, you can use these methods to track code execution time (example, how long takes to render a frame in milliseconds)
- If you are measuring async methods or server calls,
EndCheckpointmust be triggered from the methods callbacks. - Checkpoints count only the time the app is in focus by default, if you want to measure real time set
pauseOnBackgroundedtofalsewhen starting the checkpoint.DiveSDK.getInstance().StartCheckpoint(string, false).
The SDK automatically measures the time in milliseconds between both calls and sends the checkpointStarted and checkpointEnded events.
Example:
//1. Start a new checkpoint
DiveSDK.getInstance().StartCheckpoint("load_assets");
//2. Call your code methods
//3. When your task is finished, call the EndCheckpoint with the same starting name
DiveSDK.getInstance().EndCheckpoint("load_assets");
Custom Event Headers:
This is a special method used for rare tracking conditions. Use only if requested by the Dive Team.
DiveSDK.getInstance().SetCustomHeaderParam(headerName:string, headerValue:object);
Like the Custom Player Config, this must be set before launch event and the header will persist for all events in this session.
//1. Set the Custom Header & other Custom Player Config
DiveSDK.getInstance()
.SetPlayerId("34223465454")
.SetCustomHeaderParam("custom_tracking_campaing", "fb323451");
//2. Launch the sdk
DiveSDK.getInstance().Launch();
Remote Config
This service allows the client to fetch game configuration values from the API server.
Quick Start
- Set up the
ApiURLinDiveConfigandInit()the sdk - Call
GetRemoteConfig(playerId, onSuccess: (response) => void, onFail: (error) => void); - Wait for the
onSuccesscallback response - Read the
RemoteConfigResponseand access the contents
IMPORTANT : If you don't use a Custom Player ID use DiveSDK.getInstance().GetDiveDeviceId() as playerId parameter
RemoteConfigResponse (onSuccess)
- Contains a
RemoteConfigobject calledremoteConfigwith all the keys and values present on the server. - Contains a
configVersionstring - Contains the
metadataExperimentsarray with information about the active experiments on the player
Accessing the Key-Value Dictionary
You can access remote config values with GetValueOrDefault(key: string, defaultValue: any)
DiveSDK.getInstance().GetRemoteConfig(playerId, response =>
{
console.log(`Get Remote Config Success.`);
const wheelsValue = response.remoteConfig.GetValueOrDefault("wheels", 5);
const storePriceValue = response.remoteConfig.GetValueOrDefault("store_price", 99.99);
const popupEnabledValue = response.remoteConfig.GetValueOrDefault("is_popup_enabled", true);
const textValue = response.remoteConfig.GetValueOrDefault("menu_text", "Main Menu");
const offerEndTime = response.remoteConfig.GetValueOrDefault("offer_end_time", Date.now());
console.log(` > wheelsValue: ${wheelsValue}`);
console.log(` > storePriceValue: ${storePriceValue}`);
console.log(` > popupEnabledValue: ${popupEnabledValue}`);
console.log(` > menu_text: ${textValue}`);
console.log(` > offer_end_time: ${offerEndTime}`);
}, error =>
{
console.log(`Get Remote Config Failed. Error: ${error}`);
});
How Server fetch works
- SDK attempts a maximum of 3 quick retries before returning
onFail - SDK only fetch the results once every session (if the remote config was downloaded correctly)
- SDK will always keep a local cache of the latest successful response from the server in case the player is offline or the server is down.
- A/B Testing, Experiments and Segments are automatically handled by the server.
GDPR / CCPA
Forget Player
By using the method DiveSDK.getInstance().SetOptOut(true); you can notify Dive when a user has exercised their right to be forgotten.
This will instruct the Dive SDK to communicate the user's choice to be completely forgotten from any type of tracking on the client and/or server.
No requests from this device will be sent to the server in the future.
To resume tracking use DiveSDK.getInstance().SetOptOut(false);
This will start tracking again in the next DiveSDK.getInstance().Init(DiveConfig)
Migrating from 1.5
- Peer dependencies changed.
@react-native-async-storage/async-storage2.x andreact-native-device-info15.x are required.@sparkfabrik/react-native-idfa-aaidis no longer used; remove it and installexpo-tracking-transparency(see Quick Start). Bare React Native apps neednpx install-expo-modules@latestonce. - Minimum React Native 0.76 / Expo SDK 52. Older apps should stay on the 1.5.x line.
- Public API is unchanged.
Init,Launch,RecordEvent,ScreenViewed,RecordError, checkpoints, custom headers,GetRemoteConfigandSetOptOutkeep their signatures.StartCheckpointnow honours the documented second argument (pauseOnBackgrounded).GetDiveDeviceId()is available as an alias ofGetDeviceId(). - Behaviour fixes.
user_agentis now a real string (it was serialized as an empty object), the beacon keeps running after the app returns from background, and HTTP error responses are no longer retried (only network failures are), so the server never receives duplicated events. - Import path. Import from the package name:
import { DiveSDK, EventBody } from '@divegames/dive-ts-mobile-sdk'.
Development
npm install
npm run typecheck # tsc --noEmit
npm test # jest
npm run build # emits build/ (committed; package main points there)