Getting, Setting, Persisting and Reusing UUIDs

For accurate device counting (for billing purposes) and consistent, reliable presence behavior, it is important for you to ensure that all of your applications are implemented so that each unique client (end user, device, server) uses (and reuses) its own UUID. For example:

  • device1 UUID: 15d76a39-41a9-41c7-9b4f-b6186707fd8a
  • device2 UUID: ed5b10e0-26d9-4055-ba04-57eddab9fc32
  • device3 UUID: c98f2b5c-f97d-4b59-aea8-0f52250558ca
  • ... and so on.


When you instantiate a PubNub instance (i.e. new PubNub()), the PubNub SDK generates a new UUID for you. So if your app instantiates a PubNub instance 3 times in a single day for one device, than it will be counted as 3 different UUIDs, for that single device. So it is important that your application reuses the UUID on each device. You can accomplish this by either passing the UUID to the device upon successful login or persist the UUID on the device where it can be retrieved the next time the PubNub instance is instantiated.


JavaScript/Web

// init PUBNUB object with UUID value
var pubnub = new PubNub({
    publishKey: "yourPubKey",
    subscribeKey: "yourSubKey",
    uuid: customUUID || PubNub.generateUUID()
});


That last line of code might be a little subtle and might require further explanation. If you did not include uuid parameter at all, the PubNub JavaScript SDK will automatically generate a UUID for you and save it to the browser's localStorage under the key name [subKey]+"uuid". So if your subKey is "sub-c-12345-67890", then the UUID will be stored under the key name "sub-c-1245-67890uuid". The variable customUUID is assumed to be a UUID that you are passing back from your server as part of the response from a successful login. If for some reason the customUUID was undefined (null) then we are using PubNub.generateUUID function to provide a UUID as a placeholder. Providing a value for the uuid parameter here will result in that value getting saved in the same localStorage key.

It is not required that you use the PubNub.generateUUID API to create a UUID and this format of UUID is not required (any string will do up to 64 characters). You could use the end users' username, email address or some hash of values from the user profile. Just consider that whatever you use will be visible to other users (if a user peeks behind the scenes using the browser console or other tools).


Server Side UUIDs

On the server side, each server instance should also set and reuse a UUID. Many server side implementations of PubNub publish one message at a time. This typically means that when PubNub is instantiated, the publish is executed and then the process ends until the next publish where PubNub is instantiated again. This use case would generate a new UUID with every publish which would result in extreme over counting. Once solution would be to keep the PubNub instance from being destroyed so that it does not have to be instantiated each time. But there is always a chance that the entire process is restarted so you should still be persisting the UUID for reuse. Best practice would be to include the UUID in the processes environment config file along with the pub/sub keys, your database connection and such.

Some SDKs automatically reuse a UUID that is generated for you (iOS and JavaScript/Web SDKs). But you should use your own UUID that represents each one of your end users and also one for each server instance. The JavaScript SDK already has the following implementation that it uses by default, but it you might want to set your own UUID.


Java/Server

private PubNub pubnub;

protected void getPubNub() {
    if (pubnub == null) {
    pubnub = new PubNub(configPubNub());
  }
  return pubnub;
}

public PNConfiguration configPubNub() throws IOException {
  try {
    PNConfiguration pnconfig = new PNConfiguration();
    Properties prop = new Properties();
    InputStream in = getClass().getClassLoader().getResourceAsStream("config.properties");

    if (inputStream != null) {
      prop.load(inputStream);
    } 
    else {
      throw new FileNotFoundException("'config.properties' not found in classpath");
    }

    pnconfg.setPublishKey(prop.getProperty("publishKey"));
    pnconfg.setSubscribeKey(prop.getProperty("subscribeKey"));

    String uuid = prop.getProperty("UUID");
    if (uuid == null || uuid.equals("")) {
      uuid = java.util.UUID.randomUUID().toString();
      prop.setProperty("UUID", uuid);
    }
    pnconfg.setUUID(uuid);
    
    return pnconfig;
  } 
  catch (Exception e) {
    // handle exception
  } 
  finally {
    inputStream.close();
  }
}


In the above Java code snippet, the assumption is that you have a data member named pubnub that will hold an instance of PubNub. Using the singleton pattern, the getPubNub method will create, and configure, the instance if it has not yet been instantiated. There are various ways to implement the above but this is a simple example of how you might go about it.

The getPubNub method will instantiate a PubNub instance by calling the configPubNub method, which simply reads a configuration properties file, config.properties, which contains PubNub properties (and possibly other application properties) like the publish/subscribe/secret keys, a UUID (possibly null upon deployment) and other properties required for PubNub configuration. You might get this information from a database and the properties are preloaded into environment variables at a higher scope prior to calling getPubNub


Generic Algorithm

The API for UUID storage will vary per SDK but the generic algorithm remains the same:

  1. Retrieve the UUID value from device's local storage
    • if UUID value exists, skip to step 2
    • else UUID does not exist yet (first time app launch/init)
      • generate a new UUID (or use one passed to your client from your server as part of the login process)
      • save UUID to local device's storage (localStorage, user profile, user defaults, etc.)
  2. set the UUID and init PubNub instance (with some SDKs you init PubNub, then set UUID)