CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

pubnub/pubnub-app-developer

Build real-time applications with PubNub pub/sub messaging

Agent Success

Agent success rate when using this tile

94%

Improvement

Agent success rate improvement when using this tile compared to baseline

1.29x

Baseline

Agent success rate without this tile

73%

Overview
Eval results
Skill reviews
Files

sdk-patterns.mdreferences/

PubNub SDK Initialization and Configuration

SDK Initialization

JavaScript/TypeScript

import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'pub-c-...',
  subscribeKey: 'sub-c-...',
  userId: 'unique-user-id',           // REQUIRED - persistent identifier
  // Optional configuration
  ssl: true,                           // Default: true (use HTTPS)
  authKey: 'auth-token',              // For Access Manager authentication
  cipherKey: 'my-cipher-key',         // For AES-256 message encryption
  logVerbosity: false,                // Enable debug logging
  enableEventEngine: true             // Recommended for better connection management
});

Python

from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub

pnconfig = PNConfiguration()
pnconfig.publish_key = 'pub-c-...'
pnconfig.subscribe_key = 'sub-c-...'
pnconfig.uuid = 'unique-user-id'      # REQUIRED
pnconfig.ssl = True                    # Default: True
pnconfig.auth_key = 'auth-token'      # For Access Manager
pnconfig.cipher_key = 'my-cipher-key' # For encryption

pubnub = PubNub(pnconfig)

Swift (iOS)

import PubNub

let config = PubNubConfiguration(
    publishKey: "pub-c-...",
    subscribeKey: "sub-c-...",
    userId: "unique-user-id"
)
config.authKey = "auth-token"        // For Access Manager
config.cipherKey = "my-cipher-key"   // For encryption

let pubnub = PubNub(configuration: config)

Kotlin (Android)

import com.pubnub.api.PNConfiguration
import com.pubnub.api.PubNub
import com.pubnub.api.UserId

val config = PNConfiguration(UserId("unique-user-id")).apply {
    publishKey = "pub-c-..."
    subscribeKey = "sub-c-..."
    authKey = "auth-token"          // For Access Manager
    cipherKey = "my-cipher-key"     // For encryption
}

val pubnub = PubNub(config)

Java

import com.pubnub.api.PNConfiguration;
import com.pubnub.api.PubNub;

PNConfiguration config = new PNConfiguration();
config.setPublishKey("pub-c-...");
config.setSubscribeKey("sub-c-...");
config.setUuid("unique-user-id");    // REQUIRED
config.setAuthKey("auth-token");     // For Access Manager
config.setCipherKey("my-cipher-key"); // For encryption

PubNub pubnub = new PubNub(config);

userId (UUID) Requirements

Critical Rules

  1. Always Required: SDK will error without a userId
  2. Must Be Unique: Each user/device needs a distinct identifier
  3. Must Be Persistent: Reuse the same userId across sessions
  4. Max Length: 64 characters

Bad Practices

// DON'T: Generate random UUID on each session
userId: crypto.randomUUID()  // Creates billing/presence issues

// DON'T: Use undefined or empty
userId: ''  // Will cause errors
userId: undefined  // Will cause errors

Good Practices

// DO: Generate once and persist
function getUserId() {
  let userId = localStorage.getItem('pubnub_user_id');
  if (!userId) {
    userId = `user_${crypto.randomUUID()}`;
    localStorage.setItem('pubnub_user_id', userId);
  }
  return userId;
}

// DO: Use authenticated user ID from your system
userId: authenticatedUser.id

// DO: Use device identifier for IoT
userId: `device_${deviceSerialNumber}`

Event Listeners

JavaScript Listener Pattern

pubnub.addListener({
  // Receive messages
  message: (event) => {
    console.log('Message:', event.message);
    console.log('Channel:', event.channel);
    console.log('Publisher:', event.publisher);
    console.log('Timetoken:', event.timetoken);
  },

  // Connection status
  status: (statusEvent) => {
    console.log('Status category:', statusEvent.category);
    console.log('Affected channels:', statusEvent.affectedChannels);

    switch (statusEvent.category) {
      case 'PNConnectedCategory':
        console.log('Connected to PubNub');
        break;
      case 'PNReconnectedCategory':
        console.log('Reconnected after disconnect');
        break;
      case 'PNDisconnectedCategory':
        console.warn('Disconnected - will auto-reconnect');
        break;
      case 'PNNetworkDownCategory':
        console.error('Network is down');
        break;
      case 'PNNetworkUpCategory':
        console.log('Network restored');
        break;
      case 'PNAccessDeniedCategory':
        console.error('Access denied - check auth token');
        break;
    }
  },

  // Presence events (if subscribed with presence)
  presence: (presenceEvent) => {
    console.log('Action:', presenceEvent.action);  // join, leave, timeout
    console.log('UUID:', presenceEvent.uuid);
    console.log('Occupancy:', presenceEvent.occupancy);
  },

  // Signal events
  signal: (signalEvent) => {
    console.log('Signal:', signalEvent.message);
  },

  // Message actions (reactions, etc.)
  messageAction: (actionEvent) => {
    console.log('Action type:', actionEvent.data.type);
    console.log('Action value:', actionEvent.data.value);
  }
});

Python Listener Pattern

from pubnub.callbacks import SubscribeCallback
from pubnub.enums import PNStatusCategory

class MySubscribeCallback(SubscribeCallback):
    def message(self, pubnub, message):
        print(f'Message: {message.message}')
        print(f'Channel: {message.channel}')
        print(f'Publisher: {message.publisher}')

    def status(self, pubnub, status):
        if status.category == PNStatusCategory.PNConnectedCategory:
            print('Connected')
        elif status.category == PNStatusCategory.PNReconnectedCategory:
            print('Reconnected')
        elif status.category == PNStatusCategory.PNDisconnectedCategory:
            print('Disconnected')

    def presence(self, pubnub, presence):
        print(f'Action: {presence.event}')
        print(f'UUID: {presence.uuid}')

pubnub.add_listener(MySubscribeCallback())

Common Configuration Options

OptionDescriptionDefault
publishKeyKey for publishing messagesRequired
subscribeKeyKey for subscribing to channelsRequired
userIdUnique client identifierRequired
sslUse HTTPS connectionstrue
authKeyAccess Manager authentication tokenNone
cipherKeyAES-256 encryption keyNone
logVerbosityEnable debug loggingfalse
enableEventEngineModern connection managementVaries
heartbeatIntervalPresence heartbeat interval (seconds)300
presenceTimeoutPresence timeout (seconds)300

Error Handling Patterns

Publish with Error Handling

async function safePublish(channel, message) {
  try {
    const result = await pubnub.publish({ channel, message });
    console.log('Published with timetoken:', result.timetoken);
    return result;
  } catch (error) {
    console.error('Publish failed:', error.status);

    if (error.status?.category === 'PNAccessDeniedCategory') {
      // Refresh auth token and retry
      await refreshAuthToken();
      return pubnub.publish({ channel, message });
    }
    throw error;
  }
}

Connection Retry Logic

let reconnectAttempts = 0;
const MAX_RECONNECT_ATTEMPTS = 5;

pubnub.addListener({
  status: (statusEvent) => {
    if (statusEvent.category === 'PNDisconnectedCategory') {
      reconnectAttempts++;

      if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
        console.error('Max reconnection attempts reached');
        // Notify user, show offline UI
      }
    } else if (statusEvent.category === 'PNConnectedCategory' ||
               statusEvent.category === 'PNReconnectedCategory') {
      reconnectAttempts = 0;
    }
  }
});

Cleanup and Lifecycle

React Component Example

import { useEffect, useRef } from 'react';
import PubNub from 'pubnub';

function ChatComponent({ userId, channel }) {
  const pubnubRef = useRef(null);

  useEffect(() => {
    // Initialize
    const pubnub = new PubNub({
      publishKey: process.env.REACT_APP_PUBNUB_PUB_KEY,
      subscribeKey: process.env.REACT_APP_PUBNUB_SUB_KEY,
      userId
    });
    pubnubRef.current = pubnub;

    // Add listener
    const listener = {
      message: (event) => {
        // Handle messages
      }
    };
    pubnub.addListener(listener);

    // Subscribe
    pubnub.subscribe({ channels: [channel] });

    // Cleanup on unmount
    return () => {
      pubnub.removeListener(listener);
      pubnub.unsubscribeAll();
    };
  }, [userId, channel]);

  return (/* ... */);
}

Page Unload Cleanup

window.addEventListener('beforeunload', () => {
  if (pubnub) {
    pubnub.unsubscribeAll();
  }
});

Best Practices Summary

  1. Initialize once: Create a single PubNub instance per user session
  2. Add listeners before subscribing: Ensure you don't miss events
  3. Handle all status categories: Provide good UX during disconnects
  4. Clean up on unmount: Unsubscribe to prevent memory leaks
  5. Never expose Secret Key: Only use on server-side code
  6. Persist userId: Avoid random IDs that change per session
  7. Use try/catch: Handle publish/subscribe errors gracefully
tessl i pubnub/pubnub-app-developer@0.1.4

SKILL.md

tile.json