Setting Up In-App Messages (Developer Guide)

This guide explains how to set up in-app messaging and client side tracking for Userlist. In addition to this detailed approach, you can also use one of our integration libraries that does most of the heavy lifting for you.

Language / Framework Links
Ruby Documentation, Repository
Ruby on Rails Documentation, Repository

We're continuously adding libraries for more languages. If your language or framework isn't listed yet, please follow the guide below.

Adding the JavaScript snippet

In order to use both in-app messages and client side tracking, you have to include a small JavaScript snippet in your application's layout for signed in users.

1
2
<script>window.userlist=window.userlist||function(){(userlist.q=userlist.q||[]).push(arguments)};</script>
<script async data-userlist="insert-generated-user-token-here" src="https://js.userlist.com/v1"></script>

Please note the data-userlist attribute on the second script tag. You have to pass a generated user token in here. This is a unique, signed token that authenticates the current user with Userlist's servers. This ensures that only this particular user's record can be updated and that they are the only ones who can read the messages intended for them.

Generating user tokens

The user token has to be generated on the server side. This ensures that your Push Key stays secret and nobody else can issue valid user tokens.

The user tokens are JSON Web Tokens (JWT), signed using your application's Push Key.

They require two claims in the payload. Specifically, that's sub (the user's unique identifier) and exp (the token's expiration time). In addition you must provide the kid (our Push Id in the token's header).

There are JWT libraries for almost all programming languages. Nonetheless, the process to generate the tokens is fairly simple, even without a dedicated library.

Ruby Example

Here's an example showing how to generate a token using Ruby and its standard library.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
require 'json'
require 'openssl'
require 'base64'

# Url safe Base64 encoding without a trailing =
def base64(string)
   Base64.urlsafe_encode64(string).tr('=', '')
end

# Generate a JSON string from the given hash
def json(hash)
   JSON.generate(hash)
end

# HMAC signature using the SHA256 algorithm
def hmac256(data, key)
   digest = OpenSSL::Digest.new('SHA256')
   OpenSSL::HMAC.digest(digest, key, data)
end

push_key = 'EqNgYUpW3oURUGMMU8IDnSWy4SwTLs0p' # Your applications's Push Key
push_id  = 'OMNfBvInB8g5AZbwnpiTymlccEYm6nLc' # Your applications's Push Id
payload = {
   sub: 'user-1', # The user's unique identifier
   exp: Time.now.to_i + 300 # The expiration time as unix timestamp in UTC
}

header = {
   kid: push_id,
   alg: 'HS256'
}

encoded_header = base64(json(header))
encoded_payload = base64(json(payload))
encoded_header_and_payload = "#{encoded_header}.#{encoded_payload}"

encoded_signature = base64(hmac256(encoded_header_and_payload, push_key))

token = "#{encoded_header}.#{encoded_payload}.#{encoded_signature}"

PHP Example

Here's an example showing how to generate a token using PHP and its standard library.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Url safe Base64 encoding without a trailing =
function base64($string) {
  return rtrim(strtr(base64_encode($string), '+/', '-_'), '=');
}

// Generate a JSON string from the given map
function json($data) {
  return json_encode($data);
}

// HMAC signature using the SHA256 algorithm
function hmac256($data, $key) {
  return hash_hmac('SHA256', $data, $key, true);
}

$push_key = 'EqNgYUpW3oURUGMMU8IDnSWy4SwTLs0p'; // Your applications's Push Key
$push_id  = 'OMNfBvInB8g5AZbwnpiTymlccEYm6nLc'; // Your applications's Push Id

$payload = [
  'sub' => 'user-1',     // The user's unique identifier
  'exp' => time() + 300  // The expiration time as unix timestamp in UTC
];

$header = [
  'kid' => $push_id,
  'alg' => 'HS256',
];

$encoded_header = base64(json($header));
$encoded_payload = base64(json($payload));
$encoded_header_and_payload = "$encoded_header.$encoded_payload";

$encoded_signature = base64(hmac256($encoded_header_and_payload, $push_key));
$token = "$encoded_header.$encoded_payload.$encoded_signature";

JavaScript (Node.js) Example

The following example shows how to generate a token using JavaScript (Node.js) and its crypto library.

This snippet is intended for server side JavaScript. Do not generate the token on the client side, as this would expose your secret Push Key and allow attackers to read and update all of your user's data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var crypto = require('crypto');

// Url safe Base64 encoding without a trailing =
function base64(data) {
  return Buffer.from(data)
    .toString('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}

// Generate a JSON string from the given object
function json(data) {
  return JSON.stringify(data)
}

// HMAC signature using the SHA256 algorithm
function hmac256(data, secret) {
  return crypto
    .createHmac('sha256', secret)
    .update(data)
    .digest();
}

var pushKey = 'EqNgYUpW3oURUGMMU8IDnSWy4SwTLs0p'; // Your applications's Push Key
var pushId  = 'OMNfBvInB8g5AZbwnpiTymlccEYm6nLc'; // Your applications's Push Id

var payload = {
   sub: 'user-1', // The user's unique identifier
   exp: Number(new Date()) + 300 // The expiration time as unix timestamp in UTC
};

var header = {
   kid: pushId,
   alg: 'HS256'
};

var encodedHeader = base64(json(header));
var encodedPayload = base64(json(payload));
var encodedHeaderAndPayload = encodedHeader + '.' + encodedPayload;

var encodedSignature = base64(hmac256(encodedHeaderAndPayload, pushKey));

var token = encodedHeader + '.' + encodedPayload + '.' + encodedSignature;

Python Example

This example shows how to generate a token using Python and its standard library.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import base64
import json
import hmac
import hashlib
import time

# Url safe Base64 encoding without a trailing =
def base64_encode(data):
  return base64.urlsafe_b64encode(data).replace('=', '')

# Generate a JSON string from the given dictionary
def json_encode(data):
  return json.dumps(data)

# HMAC signature using the SHA256 algorithm
def hmac256(data, secret):
  return hmac.new(secret, data, hashlib.sha256).digest()

push_key = 'EqNgYUpW3oURUGMMU8IDnSWy4SwTLs0p' # Your applications's Push Key
push_id  = 'OMNfBvInB8g5AZbwnpiTymlccEYm6nLc' # Your applications's Push Id

payload = {
   'sub': 'user-1', # The user's unique identifier
   'exp': time.time() + 300 # The expiration time as unix timestamp in UTC
}

header = {
   'kid': push_id,
   'alg': 'HS256'
}

encoded_header = base64_encode(json_encode(header))
encoded_payload = base64_encode(json_encode(payload))
encoded_header_and_payload = encoded_header + '.' + encoded_payload

encoded_signature = base64_encode(hmac256(encoded_header_and_payload, push_key))

token = encoded_header + '.' + encoded_payload + '.' + encoded_signature

C# / .NET Example

This example shows how to generate a token using C# and .NET 5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Collections;
using System.Text.Json;
using System.Security.Cryptography;

public class Program
{
  public static void Main()
  {
    var pushKey = "EqNgYUpW3oURUGMMU8IDnSWy4SwTLs0p";
    var pushId = "OMNfBvInB8g5AZbwnpiTymlccEYm6nLc";

    var payload = new Hashtable(){
      { "sub", "user-1" },
      { "exp", DateTimeOffset.Now.ToUnixTimeSeconds() + 300 }
    };

    var header = new Hashtable(){
      { "kid", pushId },
      { "alg", "HS256" }
    };

    var encodedHeader = Base64Encode(JsonEncode(header));
    var encodedPayload = Base64Encode(JsonEncode(payload));
    var encodedHeaderAndPayload = $"{encodedHeader}.{encodedPayload}";

    var encodedSignature = Base64Encode(Hmac256(StringToBytes(encodedHeaderAndPayload), pushKey));
    var token = $"{encodedHeader}.{encodedPayload}.{encodedSignature}";

    Console.WriteLine(token);
  }

  public static byte[] StringToBytes(string data) {
    return System.Text.Encoding.UTF8.GetBytes(data);
  }

  public static byte[] JsonEncode(object data) {
    var json = JsonSerializer.Serialize(data);
    return StringToBytes(json);
  }

  public static string Base64Encode(byte[] data) {
    return System.Convert.ToBase64String(data).Replace('/', '_').Replace('+', '-').TrimEnd('=');
  }

  public static byte[] Hmac256(byte[] data, string secret) {
    var hmac = new HMACSHA256(StringToBytes(secret));
    return hmac.ComputeHash(data);
  }
}

Client side tracking

After adding the tracking script including the generated user token, you're all set to send in-app messages. In addition, the tracking script also allows you to update the user's properties and to track custom events in the client's browser. See this article for the detailed instructions. Please ensure that those calls are made after the included tracking script, either by placing these calls below the script tags in your HTML or by using the page load event to delay execution.

Can I use my Segment snippet?

If you're using our Segment integration, you might be wondering whether their JavaScript snippet will work for sending in-app messages via Userlist. The short answer is no: you have to include the Userlist snippet directly.

Book your discovery demo

Let's see how Userlist fits into the bigger picture of your SaaS business. You'll learn about our automation features, integrations, proven lifecycle frameworks, and how we can help you hit your SaaS growth targets.