Teak Features in Unity

Identify User

Teak’s functionality depends on knowing when a user plays and on what device they play.

At every game launch, send the player’s ID to Teak using Teak.Instance.IdentifyUser().

Example
// ...
Teak.UserConfiguration userConfiguration = new Teak.UserConfiguration {};
Teak.Instance.IdentifyUser(YOUR_USER_ID, userConfiguration);

Make sure that your user ID is a unique ID for the player in your game.

What Player ID should you use?

Your game probably has a user ID to store progress, coin balances, and other useful data. Use that ID with Teak too.

  • It should be uniquely identify the current user.

  • Ideally the same ID that is used in your game’s backend.

  • Send it as early as possible in the game’s lifecycle.

Having a consistent ID between your game makes customer support easier, and makes life easier for your analytics team.

If you need to change players during a session, call Teak.Instance.IdentifyUser() with the other player’s id. Teak will automatically end the current player’s session and start a new session for the new player id.

User Configuration

Additional data, such as a player’s email address and Facebook ID, can be passed to Teak by setting the appropriate fields on the UserConfiguration object passed to Teak.Instance.IdentifyUser().

If you need to update any of this additional data during a game session, call Teak.Instance.IdentifyUser() with an appropriately configured UserConfiguration object. Teak.Instance.IdentifyUser() will never clear or remove information about a player, and fields that are not set on the UserConfiguration object will be ignored.

Request Notification Permissions

On iOS and Android 13 and greater you are required to ask the user if you can send them notifications. Do that with the Teak.Instance.RegisterForNotifications() call.

Permissions Example
// ...
StartCoroutine(Teak.Instance.RegisterForNotifications(granted => {
  Debug.Log("Player " + (granted ? "granted" : "denied") + " notification permissions.");
});

You can still make this call even if the player cannot be prompted for permissions again. In that case, the callback will be called passing in true if notification permissions are enabled, otherwise false if they are disabled.

Teak.Instance.PushNotificationState will not update until the callback is called.

Prompt a Player to Reenable Notifications

If notifications are disabled, you can prompt the player to re-enable them on the settings page for the app, and use Teak to go directly the settings for your app.

To get the state of push notifications, use Teak.Instance.PushNotificationState

NotificationState Values

Value

Description

UnableToDetermine

Unable to determine the notification state.

Enabled

Notifications are enabled, your app can send push notifications.

Disabled

Notifications are disabled, your app cannot send push notifications.

Provisional

Provisional notifications are enabled, your app can send notifications but they will only display in the Notification Center (iOS 12+ only).

NotRequested

The user has not been asked to authorize push notifications (iOS only).

Example
if (Teak.Instance.PushNotificationState == Teak.NotificationState.Disabled) {
    if (Teak.Instance.CanOpenNotificationSettings()) {
        // Show the player a screenshot or guide on how to enable push notifications from notification settings, then...
        Teak.Instance.OpenNotificationSettings();
    } else if (Teak.Instance.CanOpenSettingsAppToThisAppsSettings()) {
        // Show the player a screenshot or guide on how to enable push notifications from settings.
        // On iOS this will require that the player tap 'Notifications' after the settings app launches.
        // Then...
        Teak.Instance.OpenSettingsAppToThisAppsSettings();
    }
}

Local Notifications

Local Notifications let you schedule push notifications directly from your game code for the current player or other players. This differs from Standard push notifications, which your marketing team schedules for delivery in the Teak Dashboard.

Common use cases include informing players that their hourly bonus is ready or that a tournament is over.

Use Local Notifications when you need deeply personalized content or scheduling that the game code is better equipped to determine.

For example, an hourly bonus should be a local notification scheduled by the game, since the game will know when the hourly bonus was last claimed, and when the next bonus will be ready.

A daily bonus should be setup using a standard notification scheduled in the dashboard, since the timing is not specific to the game logic.

You should not use Local Notifications for a new player flow/new user experience or lapsing player flow. Instead, your marketing team should create Triggered Schedules for these use cases.

Although you can schedule Local Notifications in your game code, you will still coordinate with your marketing team on content created on the Teak Dashboard. Discuss and document when your game triggers Local Notifications thoroughly so your marketing team can craft the most relevant messaging.

Setup a Local Notification

Before sending, you must configure the corresponding Local Schedule on the Teak Dashboard. Doing so gives you the full benefit of Teak’s analytics, A/B testing, and Content Management System when using local notifications.

The Name you give the Schedule is the first parameter for any local notification scheduling calls. Your marketing team may already have set up some Local Schedules; be sure to ask them if they have and what names they’ve given the Local Schedules.

Schedule a Local Notification

All notification related methods are coroutines. Unless you want the method to block execution, you must use StartCoroutine.

To schedule a notification from your game, use:

IEnumerator Schedule(string scheduleName,
                     long delayInSeconds,
                     Dictionary<string, object> personalizationData,
                     System.Action<Reply> callback);

scheduleName should be the name of a Local Schedule on the Teak Dashboard.

The personalizationData parameter allows you to provide custom data that can be templated into each send using Local Notification Tags. Be sure to inform your marketing team what data you send under which keys so that the tags can be properly configured.

Example Local Notification Scheduling
// Requires a Local Schedule on the Teak Dashboard with the Name "hourly_bonus"!
StartCoroutine(
    Teak.Notification.Schedule(
        "hourly_bonus", 3600, new Dictionary<string, object> { {"coins", 100000} },
        (Teak.Notification.Reply reply) => {
            if(!reply.Error) {
                Debug.Log("Scheduled local notification to send in one hour, id is " + reply.ScheduleIds[0]);
            }
        }
    )
);

Scheduling a Long-Distance Notification

A notification which is scheduled from code, but delivered to a different player beside the current player is called a "long distance notification".

Common use cases include notifing players of friend activity and achievements.

To schedule a long-distance notification from your game, use:

IEnumerator ScheduleNotification(string scheduleName,
                                 long delayInSeconds,
                                 string[] userIds,
                                 System.Action<Reply> callback);
The maximum delay for a Long-Distance Notification is 30 days.

Canceling a Local Notification

To cancel a previously scheduled notification, use:

IEnumerator CancelScheduledNotification(string scheduleId,
                                        System.Action<Reply> callback);

Canceling all Local Notifications

To cancel all previously scheduled local notifications, use:

IEnumerator CancelAllScheduledNotifications(System.Action<Reply> callback);
This call is processed asynchronously. If you immediately call TeakNotification.ScheduleNotification() after calling TeakNotification.CancelAllScheduledNotifications() it is possible for your newly scheduled notification to also be canceled. We recommend waiting until the callback has fired before scheduling any new notifications.

Rewards

Whenever your game should grant a reward to a player Teak will let you know by sending out an event to all listeners added to Teak.Instance.OnReward.

Teak does not provide any in-game UI to inform a player if they received a reward or not. You should add a listener to Teak.Instance.OnReward which detects if the reward was granted or denied, and informs the player what happened.

This callback will be concurrent with the Teak Reward Endpoint server to server call.

Example Reward Listener
void MyRewardListener(TeakReward reward)
{
    switch (reward.Status) {
        case TeakReward.RewardStatus.GrantReward: {
            // The user has been issued this reward by Teak
            foreach(KeyValuePair<string, object> entry in reward.Reward)
            {
                Debug.Log("[Teak Unity Cleanroom] OnReward -- Give the user " +
                    entry.Value + " instances of " + entry.Key);
            }
        }
        break;

        case TeakReward.RewardStatus.SelfClick: {
            // The user has attempted to claim a reward
            // from their own social post
        }
        break;

        case TeakReward.RewardStatus.AlreadyClicked: {
            // The user has already been issued this reward
        }
        break;

        case TeakReward.RewardStatus.TooManyClicks: {
            // The reward has already been claimed its
            // maximum number of times globally
        }
        break;

        case TeakReward.RewardStatus.ExceedMaxClicksForDay: {
            // The user has already claimed their maximum number of rewards
            // of this type for the day
        }
        break;

        case TeakReward.RewardStatus.Expired: {
            // This reward has expired and is no longer valid
        }
        break;

        case TeakReward.RewardStatus.InvalidPost: {
            // Teak does not recognize this reward id
        }
        break;
    }
}

And then adding it to the Teak.Instance.OnReward event during Awake() in any MonoBehaviour:

Adding Listener to OnReward Event
void Awake()
{
    Teak.Instance.OnReward += MyRewardListener;
}

See TeakReward for more details.

Teak’s Links are an implementation of iOS Universal Links and Android App Links. These are links that open your game from a URL. Links can be incentivized with Rewards.

If the game is not installed on the device, the user will be directed to your game in the app store. On a desktop web browser, the user will be taken to the Desktop URL from your game settings.

Most of the setup for Links is covered in the getting started guide.

  • Associated Domains checkbox is checked on the Apple Developer Site.

  • ShortLink Domain is setup in the ShortLinks section of Teak Dashboard  Settings  General

  • ShortLink Domain is copied to the Teak settings in Unity.

  • Build Post-Processing is on.

The remaining items to-do are:

  1. Set a Desktop Game URL

    Go to Teak Dashboard  Settings  Facebook & Desktop Web and add the URL that should be opened when game links are clicked on desktop computers.

  2. Set a iTunes Product ID

    Used to link to the game in the App Store on devices where the game is not installed. Set this in Teak Dashboard  Settings  iOS

  3. Set a Android Package Name

    Used to link to the game in the Play Store page on devices where the game is not installed. Set this in Teak Dashboard  Settings  Android in the Android App Links section.

  4. Add Android Certificate Fingerprints

    Required for the optimal user experience on Android devices. Go to Teak Dashboard  Settings  Android and click the Add Android Certificate Fingerprints and follow the directions in the modal.

Once those are added, your game is setup to use Links. To confirm, create a new link on the dashboard and click on it on your devices. Your game should launch.

Deep Links are a way to link to specific screens in your game that will open when the game is launched from a notification or Universal Link.

These are useful for promoting new content or linking directly to sale content in the game.

For the marketing team to use Deep Links, they will have to add the URL to their notifications in the dashboard. So, keep a master list of active deep links that can be shared with your team, so everyone knows what is available for use.

Deep Linking with Teak is based on routes, which act like URLs. Route patterns may include named parameters, allowing you to pass in additional data.

Add routes using:

void RegisterRoute(string route,
                   string name,
                   string description,
                   Action<Dictionary<string, object>> action);
You need to register your deep link routes before you call IdentifyUser.
Example
void Awake()
{
    Teak.Instance.RegisterRoute("/store/:sku", "Store", "Open the store to an SKU", (Dictionary<string, object> parameters) => {
        // Any URL query parameters, or path parameters will be contained in the dictionary
        Debug.Log("Open the store to this sku - " + parameters["sku"]);
    });
}

How Routes Work

Routes work like URLs where parts of the path can be a variable. In the example above, the route is /store/:sku. Variables in the path are designated with :. So, in the route /store/:sku there is a variable named sku.

This means that if the deep link used to launch the app was /store/io.teak.test.dollar was used to open the app, it would call the function and assign the value io.teak.test.dollar to the key sku in the dictionary that is passed in.

This dictionary will also contain any URL query parameters. For example:

/store/io.teak.test.dollar?campaign=email

In this link, the value io.teak.test.dollar would be assigned to the key sku, and the value email would be assigned to the key campaign.

Deep links are passed to an application as part of the launch. The Teak SDK holds onto the deep link information and waits until your app has finished launching, and initializing. Deep links will be processed when your game calls Teak.Instance.IdentifyUser()

A Deep Link route may be added to any notification or email in the Advanced section when setting up a Message or Link. We recommend documenting what routes are implemented and how to use them, with examples, for your marketing team to add to notifications, emails, and links.

Session Attribution

Each time your game launches, Teak will pass all of the attribution data it has for the launch, if available, to all listeners added to Teak.Instance.OnPostLaunchSummary.

This callback will be called after your game calls Teak.Instance.IdentifyUser(), and is primarily intended to assist in reporting session attribution to other analytics systems.

Example PostLaunchSummary Listener
void MyPostLaunchSummaryListener(TeakPostLaunchSummary launchSummary)
{
    if (launchSummary.ChannelName == null) {
        Debug.Log("Launch not attributed by Teak");
        return;
    }

    Debug.Log("Launch attributed to " + launchSummary.ChannelName);
    Debug.Log("Launch came from click on " + launchSummary.CreativeName);
    Debug.Log("Launch was " + (launchSummary.RewardId == null ? "not" : "") + " rewarded");

    if (launchSummary.DeepLink != null) {
        Debug.Log("Launch requested to link to " + launchSummary.DeepLink);
    }
}

And then adding it to Teak.Instance.OnPostLaunchSummary event during Awake() in any MonoBehaviour:

Adding Listener to OnPostLaunchSummary Event
void Awake()
{
    Teak.Instance.OnPostLaunchSummary += MyPostLaunchSummaryListener;
}

See TeakPostLaunchSummary for more details.

Player Opt-Out Preferences

We recommend providing players with an in-game UI to manage their opt-out preferences. By keeping the UI in-game you can reduce the number of players who opt-out of all notifications from their device settings and provide a simpler experience for players to reenable notifications.

Teak also provides Opt-Out Categories which can be configured on the Dashboard. Each notification or email must be assigned to an Opt-Out Category. This allows players to opt-out of specific types of messaging while continuing to receive other notifications or emails.

Reading Player Opt-Out Preferences

Teak will inform your game of all configured Opt-Out Categories through the Teak.Instance.OnConfigurationData event.

Example OnConfigurationData Listener
void MyConfigurationDataListener(Teak.ConfigurationData configurationData) {
    foreach(Teak.Channel.Category category in configurationData.ChannelCategories) {
        Debug.Log("Opt-Out Category - Id: "+ category.Id + ", Player Facing Name: " + category.Name + ", Player Facing Description: " + category.Description);
    }
}

void Awake()
{
    Teak.Instance.OnConfigurationData += MyConfigurationDataListener;
}

After the OnConfigurationData callback is called Opt-Out Categories will also be accessible through Teak.Channel.Categories. Before the OnConfigurationData callback is called Teak.Channel.Categories will be null.

Teak will inform your game of the player’s current opt-out status through the Teak.Instance.OnUserData event.

Example OnUserData Listener
void MyUserDataListener(Teak.UserData userData) {
    Debug.Log("Player's push channel state is: " + userData.PushStatus.StateName);
    Debug.Log("Player's email channel state is: " + userData.EmailStatus.StateName);
    foreach(Teak.Channel.Category category in Teak.Channel.Categories) {
        Debug.Log("Player is " + (userData.PushStatus[category.Id] == Teak.Channel.State.OptIn ? "opted-in to" : " opted-out of") + category.Name + " for push.");
        // Note: If the player has no email address then the state will always be Teak.Channel.State.Unknown!
        Debug.Log("Player is " + (userData.EmailStatus[category.Id] == Teak.Channel.State.OptIn ? "opted-in to" : "opted-out of") + category.Name + " for email.");
    }
}

void Awake()
{
    Teak.Instance.OnUserData += MyUserDataListener;
}
Teak guarantees that OnConfigurationData will be called before OnUserData, and Teak.Channel.Categories will be available when OnUserData is called.

Updating Player Opt-Out Preferences

To change a player’s opt-out status for an entire channel, use

IEnumerator SetChannelState(Channel.Type channel,
                            Channel.State state,
                            System.Action<Channel.Reply> callback);
Example
// Opt out of all push notifications
StartCoroutine(Teak.Instance.SetChannelState(Teak.Channel.PlatformPush, Teak.Channel.State.OptOut, (Teak.Channel.Reply reply) => {
    if(reply.Error == false && reply.State == Teak.Channel.State.OptOut) {
        Debug.Log("Opted player out of push");
    }
}));
Changing a player’s opt-out status may fail if the player is not reachable by the given channel. In this case reply.Error will be true, and reply.Errors will be a dictionary containing more information.

To change a player’s opt-out status for a single Opt-Out Category, use

IEnumerator SetCategoryState(Channel.Type channel,
                             string category,
                             Channel.State state,
                             System.Action<Channel.Reply> callback);
Example
// Opt a player out of the emails from the 'sales' Opt-Out Category
// Note: Will only work if there is an Opt-Out Category with the Id 'sales'!
StartCoroutine(Teak.Instance.SetCategoryState(Teak.Channel.Email, "sales", Teak.Channel.State.OptOut, (TeakChannel.Reply reply) => {
    if(reply.Error == false && reply.State == Teak.Channel.State.OptOut) {
        Debug.Log("Opted player out of emails for " + reply.Category);
    }
}));

Player Properties

Teak can store up to 16 numeric, and 16 string properties per player. These properties can then be used for targeting.

You do not need to register the property in the Teak Dashboard prior to sending them from your game, however you will need to register them in the Teak Dashboard before using them in targeting.

Numeric Property

To set a numeric property, use
void SetNumericAttribute(string key,
                         double value);
Example
Teak.Instance.SetNumericAttribute("coins", new_coin_balance);

String Property

To set a string property, use:

void SetStringAttribute(string key,
                        string value);
Example
Teak.Instance.SetStringAttribute("last_slot", "amazing_slot_name");

Custom Analytics Events

Teak tracks a number of analytics event by default, including install, session start, in-app purchases facilitated by the platform app store, notification clicks, link clicks, and session timing, and nothing extra is needed to track them.

Teak can also track custom analytics events which can then be used for targeting. These events are automatically batched by the Teak SDK, you do not need to perform your own batching.

Event Format

Teak events are a tuple of values, 'action', 'object type' and 'object instance'. For example: ['LevelUp', 'Fishing', '13'].

Object instance, and object type are optional, but if you provide an object instance, you must also provide an object type, for example ['FishCaught', null, '13'] is not allowed, but ['FishCaught', 'Salmon'] is allowed.

Tracking an Event

To track that an event occurred, use:

void TrackEvent(string actionId,
                string objectTypeId,
                string objectInstanceId);
Example
Teak.Instance.TrackEvent("LevelUp", "Fishing", "13");

Incrementing Events

Incremented events are used for analytics which grow over time. You cannot provide negative values.

To increment an event, use:

void IncrementEvent(string actionId,
                    string objectTypeId,
                    string objectInstanceId,
                    long count);
Examples
Teak.Instance.IncrementEvent("coin_sink", "slot", "Happy Land Slots", 25000);
Teak.Instance.IncrementEvent("spin", "slot", "Happy Land Slots", 1);
// <after the spin happens>
Teak.Instance.IncrementEvent("coin_source", "slot", "Happy Land Slots", 1000000);

Payment Reporting

Teak will automatically collect information for in-app purchases made using the platform app store on iOS, Android, and Amazon Fire devices.

On Facebook Canvas, if you are using Facebook Login for Gaming, you will need to report purchases manually with:

void ReportCanvasPurchase(string rawResult);
Example
FB.Canvas.PayWithProductId(
    this.testPurchaseSku,
    "purchaseiap",
    null,
    null,
    (IPayResult result) => {
        if(!string.IsNullOrEmpty(result.Error)) {
            Debug.LogError(result.Error);
        } else {
            Teak.Instance.ReportCanvasPurchase(result.RawResult);
        }
    }
);
Teak will automatically deduplicate reported purchases, including manually reported and automatically collected purchases. It is always safe to manually report Facebook Canvas purchases.

Logout

You can log out the current player using Logout. If the player is logged out, Teak will not process deep links or rewards until a player is logged in, via Teak.Instance.IdentifyUser().

The current device will remain associated with the last player id passed to IdentifyUser, and Teak will continue to send notifications to the device even if you call Logout. In general we do not recommend using Logout unless you have very specific needs and can handle some players potentially being denied notification or email rewards.

Log Events

Teak communicates via semi-structured log events. You can view these in the device logs, but we also expose an event that you can use to listen for these logs inside Unity, as well as a wrapper class to help work with the log messages.

Getting Log Events from Teak

Create a handler for log events:

void HandleLogEvent(Dictionary<string, object> logData) {
    Debug.Log(new TeakLogEvent(logData));
}

And assign it to Teak.Instance.OnLogEvent:

Teak.Instance.OnLogEvent += HandleLogEvent;

See TeakLogEvent for more details.