<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: PubNub</title>
    <description>The latest articles on DEV Community by PubNub (@pubnub).</description>
    <link>https://dev.to/pubnub</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F764%2Fd441ff37-9b59-44ad-ba27-34faf3a731dd.jpg</url>
      <title>DEV Community: PubNub</title>
      <link>https://dev.to/pubnub</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pubnub"/>
    <language>en</language>
    <item>
      <title>Documentation Release Notes - January 2026</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Fri, 30 Jan 2026 13:54:40 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-january-2026-250i</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-january-2026-250i</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2026/january?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2026/january&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;January kicked off the year with a focus on developer experience improvements and continued modernization of our SDK documentation.&lt;/p&gt;

&lt;p&gt;The biggest addition this month was a comprehensive JavaScript environment setup guide covering Node.js versions, package managers (npm, yarn, pnpm, bun), TypeScript configuration, and modern build tools. We also added Bun support to the JavaScript Chat SDK and improved installation instructions across all Chat SDKs.&lt;/p&gt;

&lt;p&gt;On the SDK side, we continued the HereNow pagination work from November 2025, adding &lt;code&gt;limit&lt;/code&gt; and &lt;code&gt;offset&lt;/code&gt; parameters to Swift, JavaScript, and Kotlin Chat SDKs. We also completed the migration of Swift Chat SDK code snippets to use repository-sourced examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Troubleshooting improvements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We improved the &lt;a href="https://pubnub.com/docs/general/resources/troubleshooting" rel="noopener noreferrer"&gt;troubleshooting documentation&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/sdks/javascript/status-events" rel="noopener noreferrer"&gt;JavaScript SDK status events&lt;/a&gt; based on user feedback.&lt;/p&gt;

&lt;p&gt;The troubleshooting page now includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Clear HTTP status code tables for success and error codes&lt;/li&gt;
&lt;li&gt;  Detailed guidance on handling concurrent updates (HTTP 412) with ETag&lt;/li&gt;
&lt;li&gt;  Links to SDK-specific troubleshooting and status event references&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Legacy provisioning API deprecation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We updated the &lt;a href="https://pubnub.com/docs/general/setup/limits" rel="noopener noreferrer"&gt;API limits documentation&lt;/a&gt; to clarify keyset limits for different account tiers and added deprecation notices for the legacy provisioning API.&lt;/p&gt;

&lt;p&gt;Account Tier&lt;/p&gt;

&lt;p&gt;Keyset Limit&lt;/p&gt;

&lt;p&gt;Free&lt;/p&gt;

&lt;p&gt;3 keysets (hard limit)&lt;/p&gt;

&lt;p&gt;Starter&lt;/p&gt;

&lt;p&gt;Unlimited&lt;/p&gt;

&lt;p&gt;Pro&lt;/p&gt;

&lt;p&gt;Unlimited&lt;/p&gt;

&lt;p&gt;For programmatic keyset management, use the &lt;a href="https://pubnub.com/docs/admin-api" rel="noopener noreferrer"&gt;Admin API&lt;/a&gt; instead of the deprecated provisioning endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JavaScript environment setup
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We added a comprehensive &lt;a href="https://pubnub.com/docs/sdks/javascript/environment-setup" rel="noopener noreferrer"&gt;JavaScript environment setup guide&lt;/a&gt; covering everything you need to configure a modern JavaScript environment for PubNub development.&lt;/p&gt;

&lt;p&gt;The guide covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Node.js versions&lt;/strong&gt; - PubNub's JavaScript SDK requires Node.js 20 or later for server-side applications&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Package managers&lt;/strong&gt; - Installation instructions for npm, yarn, pnpm, and bun&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TypeScript configuration&lt;/strong&gt; - Recommended &lt;code&gt;tsconfig.json&lt;/code&gt; settings for PubNub projects&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Build tools&lt;/strong&gt; - Setup guides for Vite, Next.js, Remix, and Angular&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ES Modules vs CommonJS&lt;/strong&gt; - Guidance on import styles and Node.js ESM support&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;React Native&lt;/strong&gt; - Setup for both Expo and React Native CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Package manager comparison:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Feature&lt;/p&gt;

&lt;p&gt;npm&lt;/p&gt;

&lt;p&gt;yarn&lt;/p&gt;

&lt;p&gt;pnpm&lt;/p&gt;

&lt;p&gt;bun&lt;/p&gt;

&lt;p&gt;Bundled with Node.js&lt;/p&gt;

&lt;p&gt;Yes&lt;/p&gt;

&lt;p&gt;No&lt;/p&gt;

&lt;p&gt;No&lt;/p&gt;

&lt;p&gt;No&lt;/p&gt;

&lt;p&gt;Install speed&lt;/p&gt;

&lt;p&gt;Moderate&lt;/p&gt;

&lt;p&gt;Fast&lt;/p&gt;

&lt;p&gt;Very fast&lt;/p&gt;

&lt;p&gt;Very fast&lt;/p&gt;

&lt;p&gt;Disk space efficiency&lt;/p&gt;

&lt;p&gt;Moderate&lt;/p&gt;

&lt;p&gt;Moderate&lt;/p&gt;

&lt;p&gt;Very efficient&lt;/p&gt;

&lt;p&gt;Efficient&lt;/p&gt;

&lt;p&gt;Workspaces support&lt;/p&gt;

&lt;p&gt;Yes&lt;/p&gt;

&lt;p&gt;Yes&lt;/p&gt;

&lt;p&gt;Yes&lt;/p&gt;

&lt;p&gt;Yes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript setup example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1import PubNub from 'pubnub';2
3const pubnub = new PubNub({4    publishKey: 'your-publish-key',5    subscribeKey: 'your-subscribe-key',6    userId: 'your-user-id'7});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bun support in Chat SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We added &lt;a href="https://bun.sh/" rel="noopener noreferrer"&gt;Bun&lt;/a&gt; package manager installation instructions to the &lt;a href="https://pubnub.com/docs/chat/chat-sdk" rel="noopener noreferrer"&gt;JavaScript Chat SDK documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can now install the JavaScript Chat SDK using Bun:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bun add @pubnub/chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JavaScript Chat SDK now supports all major package managers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  npm&lt;/li&gt;
&lt;li&gt;  yarn&lt;/li&gt;
&lt;li&gt;  pnpm&lt;/li&gt;
&lt;li&gt;  bun
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @pubnub/chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @pubnub/chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm add @pubnub/chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bun add @pubnub/chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Chat SDK installation updates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We updated installation instructions across all Chat SDK documentation with clearer npm and yarn guidance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/chat-sdk" rel="noopener noreferrer"&gt;JavaScript Chat SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk" rel="noopener noreferrer"&gt;Kotlin Chat SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk" rel="noopener noreferrer"&gt;Swift Chat SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/unity-chat-sdk" rel="noopener noreferrer"&gt;Unity Chat SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/unreal-chat-sdk" rel="noopener noreferrer"&gt;Unreal Chat SDK&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each SDK landing page now includes consistent, easy-to-follow installation steps with all supported package managers.&lt;/p&gt;

&lt;h3&gt;
  
  
  HereNow pagination in Chat SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Continuing the &lt;a href="https://pubnub.com/docs/release-notes/2025/november#herenow-changes-across-sdks" rel="noopener noreferrer"&gt;HereNow pagination work from November 2025&lt;/a&gt;, we added &lt;code&gt;limit&lt;/code&gt; and &lt;code&gt;offset&lt;/code&gt; parameters to presence features in the &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk" rel="noopener noreferrer"&gt;Swift&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/features/users/presence" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;, and &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/presence" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt; Chat SDKs.&lt;/p&gt;

&lt;p&gt;These parameters help you efficiently retrieve presence information for high-occupancy channels:&lt;/p&gt;

&lt;p&gt;Parameter&lt;/p&gt;

&lt;p&gt;Description&lt;/p&gt;

&lt;p&gt;&lt;code&gt;limit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Default:  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;100&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Maximum number of occupants to return per channel.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;offset&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Default:  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Zero-based starting index for pagination.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;whoIsPresent()&lt;/code&gt; method now supports pagination parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1// Get a list of users present on a channel with pagination2const result = await channel.whoIsPresent({3    limit: 50,4    offset: 05})6
7console.log(`Users present: ${result.occupants.join(", ")}`)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also expanded the threads documentation in JavaScript and Kotlin Chat SDKs to include additional methods for thread management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kotlin and Java connection pool config
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We documented connection pool configuration options in the &lt;a href="https://pubnub.com/docs/sdks/kotlin/api-reference/configuration#methods" rel="noopener noreferrer"&gt;Kotlin SDK&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/sdks/java/api-reference/configuration#methods" rel="noopener noreferrer"&gt;Java SDK&lt;/a&gt; API references.&lt;/p&gt;

&lt;p&gt;These options help you fine-tune network performance for high-throughput applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Swift Chat SDK code snippets
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Following the &lt;a href="https://pubnub.com/docs/release-notes/2025/december#files-and-push-notifications-in-unity-chat-sdk" rel="noopener noreferrer"&gt;Swift Chat SDK work from December 2025&lt;/a&gt;, we completed the migration of Swift Chat SDK documentation to use the &lt;code&gt;EmbeddedCode&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;This update affects 42 documentation files across the Swift Chat SDK, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/configuration" rel="noopener noreferrer"&gt;Configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/features/channels/create" rel="noopener noreferrer"&gt;Channel operations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/features/messages/send-receive" rel="noopener noreferrer"&gt;Message handling&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/features/users/create" rel="noopener noreferrer"&gt;User management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/features/users/presence" rel="noopener noreferrer"&gt;Presence&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All code snippets are now pulled directly from the &lt;a href="https://github.com/pubnub/swift-chat-sdk" rel="noopener noreferrer"&gt;Swift Chat SDK GitHub repository&lt;/a&gt;, ensuring examples are always tested and up-to-date with the latest SDK version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Illuminate 💡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Query Builder improvements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Following the &lt;a href="https://pubnub.com/docs/release-notes/2025/december#query-builder-documentation" rel="noopener noreferrer"&gt;Query Builder introduction in December 2025&lt;/a&gt;, we enhanced the &lt;a href="https://pubnub.com/docs/illuminate/business-objects/query-builder" rel="noopener noreferrer"&gt;Query Builder documentation&lt;/a&gt; with predefined decisions information.&lt;/p&gt;

&lt;p&gt;The updated documentation now includes visual examples for all four predefined query types:&lt;/p&gt;

&lt;p&gt;Predefined Query&lt;/p&gt;

&lt;p&gt;Purpose&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Top N&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reward the top 10 users who are most engaged by message count&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bottom N&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Incentivize users who are least engaged&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-posting spam&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Detect users sending duplicate messages across multiple channels&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chat flooding spam&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Detect users posting excessive or repetitive messages in a single channel&lt;/p&gt;

&lt;p&gt;Each predefined query now shows the corresponding predefined decision template:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gvsvpu91norhef6jdmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gvsvpu91norhef6jdmy.png" alt="Predefined decision reward" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The documentation also includes new screenshots showing how to create decisions from query data fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions ⚙️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Export logs in Functions overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We added the export logs documentation to the &lt;a href="https://pubnub.com/docs/serverless/functions/overview" rel="noopener noreferrer"&gt;Functions overview&lt;/a&gt; page. This information was previously only available in the &lt;a href="https://pubnub.com/docs/general/portal/functions" rel="noopener noreferrer"&gt;Admin Portal Functions page&lt;/a&gt; and is now easier to discover when reading the serverless Functions documentation.&lt;/p&gt;

&lt;p&gt;The documentation explains how to retain Function logs long-term using &lt;a href="https://pubnub.com/docs/serverless/events-and-actions/overview" rel="noopener noreferrer"&gt;Events &amp;amp; Actions&lt;/a&gt; via &lt;a href="https://pubnub.com/docs/serverless/events-and-actions/actions/create-webhook-action" rel="noopener noreferrer"&gt;Webhook&lt;/a&gt; or &lt;a href="https://pubnub.com/docs/serverless/events-and-actions/actions/create-s3-action" rel="noopener noreferrer"&gt;S3&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Documentation Release Notes - August 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Wed, 10 Sep 2025 16:01:55 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-august-2025-3odn</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-august-2025-3odn</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/august?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/august&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In August, we made our docs more reliable to build with and easier to use day‑to‑day.&lt;/p&gt;

&lt;p&gt;We clarified wildcard subscribe behavior and presence limits, reorganized encryption into first‑class SDK pages, and added connection management guidance for Chat SDKs.&lt;/p&gt;

&lt;p&gt;Events &amp;amp; Actions gained a cleaner pagination model, a message‑types catalog, and clearer route input guidance. Unreal and PHP SDK docs now pull examples straight from GitHub, and BizOps adds an Auto Moderated messages review surface plus a clear path to choose between managed Auto Moderation and a self‑managed Functions route.&lt;/p&gt;

&lt;p&gt;Finally, every docs page now has a machine‑friendly Markdown version (with quick buttons to copy or open) to make search, automation, and AI integrations smoother.&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Push notifications docs refinements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We updated the &lt;a href="https://pubnub.com/docs/general/push/ios#prevent-self-notifications" rel="noopener noreferrer"&gt;iOS&lt;/a&gt; (APNS) and &lt;a href="https://pubnub.com/docs/general/push/android#prevent-self-notifications" rel="noopener noreferrer"&gt;Android&lt;/a&gt; (FCM) docs to show how to exclude the sender from receiving a push for their own message (APNS: &lt;code&gt;excluded_devices&lt;/code&gt;, FCM: &lt;code&gt;pn_exceptions&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We also clarified that &lt;a href="https://pubnub.com/docs/general/push/send#register-devices" rel="noopener noreferrer"&gt;mobile push registration&lt;/a&gt; targets individual channels (not channel groups), and added a new &lt;a href="https://pubnub.com/docs/general/push/mobile-push-troubleshooting#http-400-bad-request" rel="noopener noreferrer"&gt;HTTP 400 troubleshooting note&lt;/a&gt; with common causes.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Wildcard subscribe behavior and Presence constraints
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We clarified two areas in SDK and API docs.&lt;/p&gt;

&lt;p&gt;First, calling &lt;code&gt;subscribe()&lt;/code&gt; opens the connection but &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe" rel="noopener noreferrer"&gt;you still need event listeners to receive messages&lt;/a&gt;. For wildcard subscriptions, message objects include the sender in &lt;code&gt;publisher&lt;/code&gt;, the actual channel in &lt;code&gt;channel&lt;/code&gt;, and the wildcard match in &lt;code&gt;subscription&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Second, &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/presence#methods" rel="noopener noreferrer"&gt;Presence documentation&lt;/a&gt; now explicitly notes that wildcards aren’t supported for channel groups—use exact group names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encryption documentation reorganization and updates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We moved Encryption to a first‑class API reference page in each SDK and refreshed the content so it’s easier to find and apply (for example, see &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/encryption" rel="noopener noreferrer"&gt;JavaScript SDK&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The new pages cover configuring the SDK crypto module, the legacy 128‑bit vs. recommended 256‑bit AES‑CBC options, deprecation notes for method‑level cipher key parameters, and up‑to‑date encrypt/decrypt examples (including partial encryption where applicable).&lt;/p&gt;

&lt;p&gt;We also added version compatibility warnings so older clients are handled correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection management in Kotlin and JavaScript Chat SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We added connection management docs to the &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk/build/features/connection-management" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/features/connection-management" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt; Chat SDKs. They introduce a connection status listener (ONLINE/OFFLINE/ERROR) and methods to disconnect and reconnect subscriptions, with code samples and a recommended workflow for handling errors and restoring connectivity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updated logging and subscribe retry info in Dart SDK docs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We documented &lt;a href="https://pubnub.com/docs/sdks/dart/logging" rel="noopener noreferrer"&gt;logging&lt;/a&gt; and subscribe retry in the Dart SDK so you can see what’s happening and recover gracefully.&lt;/p&gt;

&lt;p&gt;You can enable structured logs at the instance level or for specific code paths and adjust verbosity at runtime.&lt;/p&gt;

&lt;p&gt;For resilience, configure the subscribe retry policy on the networking module—exponential by default, with linear or none available. Non‑subscribe requests don’t &lt;a href="https://pubnub.com/docs/sdks/dart/api-reference/configuration#retry-policy" rel="noopener noreferrer"&gt;retry&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SDK‑sourced examples in PHP and Unreal SDK docs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We &lt;a href="https://pubnub.com/docs/release-notes/2025/june#sdk-sourced-code-snippets-across-multiple-sdks" rel="noopener noreferrer"&gt;kept rolling out&lt;/a&gt; repository‑sourced, always‑current examples and standardized rendering across SDKs.&lt;/p&gt;

&lt;p&gt;Both &lt;a href="https://pubnub.com/docs/sdks/php/api-reference/publish-and-subscribe" rel="noopener noreferrer"&gt;PHP&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/sdks/unreal/api-reference/publish-and-subscribe" rel="noopener noreferrer"&gt;Unreal&lt;/a&gt; SDK docs now pull examples directly from our GitHub repos, keeping snippets up to date, tested, and aligned with the SDK repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events &amp;amp; Actions ⚡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  API documentation updates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We updated the &lt;a href="https://pubnub.com/docs/internal/ena-rest-api" rel="noopener noreferrer"&gt;Events &amp;amp; Actions API&lt;/a&gt; reference with a standardized pagination model (&lt;code&gt;page&lt;/code&gt;/&lt;code&gt;size&lt;/code&gt; plus paging metadata), a new message types catalog (&lt;code&gt;GET /v2/messages/message-types&lt;/code&gt; with filters), and clearer route input guidance using &lt;code&gt;messageTypeName&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt; instead of &lt;code&gt;messageTypeId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also added optional &lt;code&gt;subkey&lt;/code&gt; and &lt;code&gt;account_id&lt;/code&gt; parameters where relevant and refreshed examples and formatting across the docs.&lt;/p&gt;

&lt;h5&gt;
  
  
  Availability
&lt;/h5&gt;

&lt;p&gt;The Events &amp;amp; Actions API isn’t publicly available. To request access, contact &lt;a href="https://support.pubnub.com/hc/en-us/requests/new?" rel="noopener noreferrer"&gt;PubNub Support&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  BizOps Workspace 🏢
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Review auto‑moderated messages in Channel Monitor
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;If you use &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation" rel="noopener noreferrer"&gt;Auto Moderation&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/bizops-workspace/channel-monitor" rel="noopener noreferrer"&gt;Channel Monitor&lt;/a&gt; now has an &lt;a href="https://pubnub.com/docs/bizops-workspace/channel-monitor#review-auto-moderated-messages" rel="noopener noreferrer"&gt;&lt;strong&gt;Auto Moderated Messages&lt;/strong&gt; section&lt;/a&gt; for reviewing content that was automatically blocked as spam, published with masked words, or reported for review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddr3ifszngib2tea8b4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddr3ifszngib2tea8b4w.png" alt="Review auto moderated messages" width="800" height="692"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can filter by type (&lt;strong&gt;Blocked&lt;/strong&gt;, &lt;strong&gt;Reported&lt;/strong&gt;, &lt;strong&gt;Words masked&lt;/strong&gt;) and mark items as &lt;strong&gt;Not spam&lt;/strong&gt; to provide us with feedback for improving detection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pkhcfkvx1ufzq2u08c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pkhcfkvx1ufzq2u08c9.png" alt="Filter auto moderated messages" width="800" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto Moderation: managed vs self‑managed
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;Moderating user‑generated content on channels is now straightforward under one umbrella: &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation" rel="noopener noreferrer"&gt;Auto Moderation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don’t already run a &lt;code&gt;Before Publish or Fire&lt;/code&gt; Function on those channels and want a quick path, enable BizOps‑managed &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation" rel="noopener noreferrer"&gt;Auto Moderation&lt;/a&gt; to provision a dedicated moderation Function (of the &lt;code&gt;Before Publish or Fire&lt;/code&gt; type) for you. This Function applies your spam detection and word masking policies, and sends outcomes to Channel Monitor for review—no code required.&lt;/p&gt;

&lt;p&gt;If you already have a &lt;code&gt;Before Publish or Fire&lt;/code&gt; Function running on the channel, follow an &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation#auto-moderation-with-an-existing-before-publish-function" rel="noopener noreferrer"&gt;alternative path&lt;/a&gt; to create the moderation configuration in Auto Moderation and embed it inside your existing Function.&lt;/p&gt;

&lt;p&gt;The second, "self‑managed" route (called &lt;strong&gt;Generate code for Functions&lt;/strong&gt; in the Auto Moderation UI) uses the same moderation backend and your Auto Moderation configuration (&lt;code&gt;configId&lt;/code&gt;) as the managed one, so results remain consistent and visible in Channel Monitor.&lt;/p&gt;

&lt;p&gt;Because you can have only one &lt;code&gt;Before Publish or Fire&lt;/code&gt; Function per channel, choose the self‑managed option when a managed Function would conflict.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation" rel="noopener noreferrer"&gt;Auto Moderation docs&lt;/a&gt; walk through prerequisites, setup, where moderation outcomes appear (Channel Monitor), and how to move from &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation#create-configuration" rel="noopener noreferrer"&gt;managed simplicity&lt;/a&gt; to &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation#auto-moderation-with-an-existing-before-publish-function" rel="noopener noreferrer"&gt;self‑managed control&lt;/a&gt; when your app requires it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Illuminate 💡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Customize embedded Illuminate UI
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;If you embed Illuminate UI on an external site, you can now theme it to align with your brand. The docs include a &lt;a href="https://pubnub.com/docs/illuminate/embed-illuminate-ui#insert-ui-in-your-html" rel="noopener noreferrer"&gt;complete iframe example and explicit theming options&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can pass six hexadecimal color parameters in the embed URL: &lt;code&gt;primaryColor&lt;/code&gt;, &lt;code&gt;secondaryColor&lt;/code&gt;, &lt;code&gt;backgroundColor&lt;/code&gt;, &lt;code&gt;surfaceColor&lt;/code&gt;, &lt;code&gt;textPrimaryColor&lt;/code&gt;, and &lt;code&gt;textSecondaryColor&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;iframe src="https://oem.pubnub.com/embed/dashboards?embed=true&amp;amp;token=&amp;lt;token&amp;gt;&amp;amp;primaryColor=d02129&amp;amp;secondaryColor=007594&amp;amp;backgroundColor=ffffff&amp;amp;surfaceColor=f8f9fa&amp;amp;textPrimaryColor=212529&amp;amp;textSecondaryColor=6c757d" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other 🌟
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Markdown (.md) versions for every docs page
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Improvement&lt;/p&gt;

&lt;p&gt;Large language models work best with clean, predictable content. Markdown gives us structured headings, lists, tables, code fences, and admonitions that are easy to split into chunks for embeddings and retrieval. It also reduces page “noise,” keeps anchors stable, and produces deterministic diffs that automation can trust.&lt;/p&gt;

&lt;p&gt;Why the shift toward Markdown for machines/AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Clean, structured text is easier to chunk for embeddings/RAG and remains stable across builds.&lt;/li&gt;
&lt;li&gt;  Less noise than HTML (fewer scripts/DOM artifacts) and more predictable anchors/links improve retrieval accuracy.&lt;/li&gt;
&lt;li&gt;  Deterministic, diff‑friendly outputs improve automated ingestion, QA, and syncing with source repos.&lt;/li&gt;
&lt;li&gt;  Fewer custom widgets means fewer parsing failures and more usable content for AI tools and site search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To support this, we now publish a machine‑readable Markdown version of every docs page at the same URL with a &lt;code&gt;.md&lt;/code&gt; suffix. For example, you can now access the Markdown content of &lt;a href="https://www.pubnub.com/docs/general/basics/set-up-your-account?" rel="noopener noreferrer"&gt;&lt;code&gt;https://www.pubnub.com/docs/general/basics/set-up-your-account&lt;/code&gt;&lt;/a&gt; under &lt;a href="https://www.pubnub.com/docs/general/basics/set-up-your-account.md?" rel="noopener noreferrer"&gt;&lt;code&gt;https://www.pubnub.com/docs/general/basics/set-up-your-account.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Access is simple. Two buttons now appear at the top of each page:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Copy Markdown — copies the page’s .md source to your clipboard&lt;/li&gt;
&lt;li&gt; Open as Markdown — opens the &lt;code&gt;.md&lt;/code&gt; variant of the current page&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3gfpajpty80wqe33c8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3gfpajpty80wqe33c8q.png" alt="Markdown versions of docs pages - buttons" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also append &lt;code&gt;.md&lt;/code&gt; to any docs URL to load the Markdown version directly.&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Documentation Release Notes - July 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Wed, 30 Jul 2025 13:37:50 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-july-2025-1b5n</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-july-2025-1b5n</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/july?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/july&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;July was packed with partner empowerment features, enhanced security documentation, and continued SDK improvements that make PubNub easier to integrate and manage.&lt;/p&gt;

&lt;p&gt;The biggest highlight this month is our &lt;strong&gt;official public Postman collection&lt;/strong&gt; for all PubNub Core APIs — created directly in response to your feedback and search patterns we've observed in our documentation.&lt;/p&gt;

&lt;p&gt;We also delivered comprehensive &lt;strong&gt;Partner Portal documentation&lt;/strong&gt; for customer management and &lt;strong&gt;Illuminate UI embedding&lt;/strong&gt; guides for OEM (Original Equipment Manufacturer) integrations, plus made &lt;strong&gt;Auto Moderation documentation&lt;/strong&gt; publicly available.&lt;/p&gt;

&lt;p&gt;On the development experience front, we've added a &lt;strong&gt;Run in Postman button&lt;/strong&gt; throughout our REST API documentation, created a &lt;strong&gt;What's New section&lt;/strong&gt; on our homepage, and continued our SDK-sourced code snippets rollout with Unity support.&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Partner Portal documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've added comprehensive documentation for the &lt;a href="https://pubnub.com/docs/general/portal/partner-portal" rel="noopener noreferrer"&gt;Partner Portal&lt;/a&gt;, a feature that lets PubNub partners manage their end customers directly through the Admin Portal.&lt;/p&gt;

&lt;p&gt;Partners can create customer entries, assign specific apps and keysets, and enable controlled access to Illuminate functionality. We've also documented how to &lt;a href="https://pubnub.com/docs/illuminate/embed-illuminate-ui" rel="noopener noreferrer"&gt;embed Illuminate UI&lt;/a&gt; directly into partner applications for seamless OEM integrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced channel naming guidelines
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our &lt;a href="https://pubnub.com/docs/general/channels/channel-naming" rel="noopener noreferrer"&gt;channel naming documentation&lt;/a&gt; with stronger recommendations for using ASCII characters in channel names, along with an enhanced channel name validator that now warns you when using non-ASCII characters like emojis or international characters.&lt;/p&gt;

&lt;p&gt;The improvements include better cross-platform compatibility guidance and real-time validation feedback to help prevent channel naming issues across different SDKs and platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comprehensive Presence documentation overhaul
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've expanded our &lt;a href="https://pubnub.com/docs/general/presence/overview" rel="noopener noreferrer"&gt;Presence documentation&lt;/a&gt; with a comprehensive new section on &lt;strong&gt;Implicit vs. explicit Presence events&lt;/strong&gt; that explains PubNub's timer-based tracking system, configuration settings (&lt;code&gt;presenceTimeout&lt;/code&gt; vs &lt;code&gt;heartbeatInterval&lt;/code&gt;), cost vs accuracy trade-offs, and real-world configuration scenarios for different application types.&lt;/p&gt;

&lt;p&gt;The new documentation also clarifies that implicit heartbeats can be disabled through the Presence Management GUI in the Admin Portal — addressing your feedback. We also added important billing transparency to the Presence configuration table, noting that the &lt;code&gt;Generate Leave on TCP FIN or RST&lt;/code&gt; option can result in additional billable events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security documentation updates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've made helpful additions to our &lt;a href="https://pubnub.com/docs/general/setup/data-security" rel="noopener noreferrer"&gt;data security documentation&lt;/a&gt; that enterprise customers have been asking about. We clarified that all connections use TLS 1.2 for secure communication, and added guidance on how Pro customers can access SOC 2 and other compliance reports directly from the Admin Portal (or contact support if needed).&lt;/p&gt;

&lt;h3&gt;
  
  
  Platform limits and configuration updates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated several key areas of our platform documentation to make sure you have accurate, current information when planning your PubNub implementations. The &lt;a href="https://pubnub.com/docs/general/setup/limits" rel="noopener noreferrer"&gt;channel limits documentation&lt;/a&gt; now recommends multiplexing between 10 and 50 channels (updated from "no more than 30"), and clarifies that URI length limits are 32 KiB. We also refreshed &lt;a href="https://pubnub.com/docs/general/storage" rel="noopener noreferrer"&gt;message storage documentation&lt;/a&gt; with current message count limits and usage patterns.&lt;/p&gt;

&lt;p&gt;We also clarified an important detail in our &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/configuration" rel="noopener noreferrer"&gt;heartbeat configuration documentation&lt;/a&gt; — the minimum supported value for heartbeat intervals is 3 seconds due to server constraints.&lt;/p&gt;

&lt;p&gt;These updates ensure you have accurate information for planning and configuring your PubNub implementations without hitting unexpected limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  BizOps Workspace 🏢
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Auto Moderation documentation made publicly available
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've made our &lt;strong&gt;Auto Moderation documentation&lt;/strong&gt; publicly available so you can understand and plan for automated message moderation in your chat applications.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pubnub.com/docs/bizops-workspace/auto-moderation" rel="noopener noreferrer"&gt;Auto Moderation documentation&lt;/a&gt; walks you through the two main capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;AI-powered spam detection&lt;/strong&gt; — automatically block (prevent from being published) or report problematic messages&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Word masking functionality&lt;/strong&gt; — censor predefined forbidden words&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both features work through an intuitive setup wizard that guides you through configurable moderation rules.&lt;/p&gt;

&lt;p&gt;Everything runs on &lt;a href="https://pubnub.com/docs/serverless/functions/overview" rel="noopener noreferrer"&gt;Functions v2&lt;/a&gt;, which means it's reliable and scales with your application's needs. The feature itself is currently in beta and available upon request by contacting &lt;a href="//mailto:support@pubnub.com"&gt;PubNub Support&lt;/a&gt; or &lt;a href="https://www.pubnub.com/company/contact-sales/?" rel="noopener noreferrer"&gt;Sales&lt;/a&gt; — read the full documentation to understand how it works before requesting access.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Unity SDK with GitHub-sourced code examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Continuing our SDK-sourced code snippets rollout from &lt;a href="https://pubnub.com/docs/release-notes/2025/june#sdk-sourced-code-snippets-across-multiple-sdks" rel="noopener noreferrer"&gt;June 2025&lt;/a&gt;, we've added comprehensive working code examples to our &lt;a href="https://pubnub.com/docs/sdks/unity" rel="noopener noreferrer"&gt;Unity SDK documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All examples are pulled directly from our GitHub repositories, ensuring they're always tested and current with the latest SDK versions. The Unity documentation now includes complete API reference examples across all major features.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript Subscription Sets automatic subscription behavior
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've documented the &lt;strong&gt;automatic subsequent subscriptions&lt;/strong&gt; behavior for &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#modify-a-subscription-set" rel="noopener noreferrer"&gt;JavaScript SDK Subscription Sets&lt;/a&gt; — a JavaScript-only feature where adding subscriptions to an existing active set automatically subscribes to them without additional calls.&lt;/p&gt;

&lt;p&gt;The enhanced documentation includes new code examples and better organization to make subscription set modification methods easier to find and use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access Manager v3 Gradle configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've added &lt;strong&gt;Gradle configuration details&lt;/strong&gt; for Access Manager v3 in our &lt;a href="https://pubnub.com/docs/sdks/kotlin/api-reference/access-manager" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/sdks/java/api-reference/access-manager" rel="noopener noreferrer"&gt;Java&lt;/a&gt; Access Manager documentation to help with Android and JVM-based project integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events &amp;amp; Actions ⚡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New dedicated Events &amp;amp; Actions payloads page
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've created a comprehensive new &lt;a href="https://pubnub.com/docs/serverless/events-and-actions/ena-payloads" rel="noopener noreferrer"&gt;Events &amp;amp; Actions Payloads documentation page&lt;/a&gt; that centralizes all payload examples with new schema v2.1 fields for Mobile Push Notifications and Membership CRUD operations. We also converted the webhook payload table into expandable JSON blocks and improved existing examples for better accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other 🌟
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Official public Postman collection for PubNub Core APIs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've launched our &lt;strong&gt;official public &lt;a href="https://www.postman.com/pubnub-api/pubnub-s-workspace/collection/l2hxvr2/pubnub-api" rel="noopener noreferrer"&gt;Postman collection&lt;/a&gt;&lt;/strong&gt; for all PubNub Core APIs, developed in direct response to user feedback and documentation search patterns that showed you needed better ways to test and explore our REST endpoints.&lt;/p&gt;

&lt;p&gt;The collection is now available through our &lt;a href="https://pubnub.com/docs/sdks/rest-api" rel="noopener noreferrer"&gt;REST API documentation&lt;/a&gt; and directly at &lt;a href="https://www.postman.com/pubnub-api/pubnub-s-workspace/collection/l2hxvr2/pubnub-api" rel="noopener noreferrer"&gt;PubNub's Postman Workspace&lt;/a&gt;. What makes this collection special is that it includes complete API coverage for all PubNub Core services with pre-configured examples for every endpoint. Everything comes with an easy testing environment that has demo keys ready to use, plus API documentation directly in Postman so you don't have to switch back and forth between tools.&lt;/p&gt;

&lt;p&gt;This makes PubNub APIs more accessible and provides a standardized way to explore our REST endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced documentation homepage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've added a dedicated &lt;strong&gt;What's New&lt;/strong&gt; section to our &lt;a href="https://pubnub.com/docs" rel="noopener noreferrer"&gt;docs homepage&lt;/a&gt; that highlights the latest PubNub features and resources, making it easier to discover new features and stay current with platform updates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh1c2dbskgsc5adsre6w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh1c2dbskgsc5adsre6w6.png" alt="What's New section" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Run in Postman button integration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've made testing our REST APIs incredibly easy by adding &lt;strong&gt;Run in Postman&lt;/strong&gt; buttons directly in the &lt;strong&gt;Try it out&lt;/strong&gt; sections of &lt;a href="https://pubnub.com/docs/sdks/rest-api/publish-message-to-channel" rel="noopener noreferrer"&gt;every API endpoint page&lt;/a&gt;. Now when you're reading about a specific API method and want to test it immediately, you'll see a button that lets you fork our official Postman collection with just one click.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca7dy6f1plpxdx9fmpxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca7dy6f1plpxdx9fmpxy.png" alt="Run in Postman" width="800" height="1175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything comes pre-configured with demo keys and environment variables, so you can start testing immediately without any setup friction.&lt;/p&gt;

&lt;p&gt;This creates a seamless bridge between reading our documentation and hands-on API exploration. Instead of copying endpoints, finding API keys, and setting up your own requests, you can go from "I wonder how this works" to "Let me try it now" in seconds.&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Documentation Release Notes - June 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Wed, 09 Jul 2025 13:48:54 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-june-2025-36dd</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-june-2025-36dd</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/june?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/june&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;June was all about making our SDKs easier to work with and giving you better examples to learn from.&lt;/p&gt;

&lt;p&gt;The big highlight this month? We launched a brand new &lt;a href="https://pubnub.com/docs/entertainment" rel="noopener noreferrer"&gt;Sports, Media &amp;amp; Entertainment documentation section&lt;/a&gt; complete with an interactive demo showcasing real-time sports experiences. Plus, we've been busy rolling out GitHub-sourced code snippets across Swift, C#, and JavaScript SDKs, so you know the examples will always be up-to-date!&lt;/p&gt;

&lt;p&gt;We also continued our mission to improve Getting Started guides for Rust and JavaScript, expanded Chat SDKs with Platform Support docs, and added helpful troubleshooting guides for mobile development and Firebase configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Enhanced REST API documentation structure
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We gave our &lt;a href="https://pubnub.com/docs/sdks/rest-api" rel="noopener noreferrer"&gt;REST API documentation&lt;/a&gt; a makeover with better navigation and more descriptive page names for improved discoverability.&lt;/p&gt;

&lt;p&gt;What's new:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Page titles that actually tell you what each API endpoint does&lt;/li&gt;
&lt;li&gt;  Cleaner navigation that makes sense&lt;/li&gt;
&lt;li&gt;  Better linking between related endpoints&lt;/li&gt;
&lt;li&gt;  Much easier to find what you're looking for&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you're just getting started or looking for advanced configuration options, finding the right REST API endpoint should be much smoother now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved Subscribe Filtering documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We reorganized our &lt;a href="https://pubnub.com/docs/general/channels/subscribe#filtering" rel="noopener noreferrer"&gt;Subscribe Filtering documentation&lt;/a&gt; to put filtering information where it belongs - in the subscribe docs rather than scattered across different pages.&lt;/p&gt;

&lt;p&gt;This restructuring makes it much easier to find filtering guidance when you're working with subscriptions, with all the relevant information now properly organized in one place.&lt;/p&gt;

&lt;p&gt;These changes help you find filtering information more intuitively and understand how to implement filtering strategies in your subscribe operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced Chat SDK authentication documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We added authentication examples to the &lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/configuration" rel="noopener noreferrer"&gt;Chat SDK configuration documentation&lt;/a&gt;, including how to use the &lt;code&gt;authKey&lt;/code&gt; parameter with Access Manager.&lt;/p&gt;

&lt;p&gt;The updates include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  New &lt;code&gt;authKey&lt;/code&gt; configuration parameter documentation&lt;/li&gt;
&lt;li&gt;  Server-side code example for generating tokens with Access Manager&lt;/li&gt;
&lt;li&gt;  Clear guidance on initializing Chat SDK with authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These additions make it easier to implement Access Manager authentication in your chat applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message actions terminology standardization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We standardized terminology across all documentation to clarify the difference between "reactions" and "actions", updating most references to use "&lt;a href="https://pubnub.com/docs/general/messages/actions" rel="noopener noreferrer"&gt;actions&lt;/a&gt;" for consistency. We also added clearer channel ID requirements for Pub/Sub API usage.&lt;/p&gt;

&lt;p&gt;This comprehensive update touched:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  General message documentation to use consistent "actions" terminology&lt;/li&gt;
&lt;li&gt;  All SDK API reference documentation for message actions&lt;/li&gt;
&lt;li&gt;  Chat SDK documentation across all platforms&lt;/li&gt;
&lt;li&gt;  REST API documentation with enhanced channel ID clarification for Pub/Sub API operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This standardization makes it much clearer when we're referring to the broader concept of message actions versus specific reaction implementations, while also providing better guidance on channel ID requirements for API usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced troubleshooting documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We added new troubleshooting guides for key PubNub services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://pubnub.com/docs/general/push/android" rel="noopener noreferrer"&gt;Firebase Cloud Messaging&lt;/a&gt;&lt;/strong&gt;: Better FCM setup instructions and troubleshooting for push notifications&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://pubnub.com/docs/general/portal/troubleshooting" rel="noopener noreferrer"&gt;Admin Portal&lt;/a&gt;&lt;/strong&gt;: New guide for registration and reCAPTCHA issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These guides tackle common developer pain points with step-by-step solutions for configuration and integration challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SDK-sourced code snippets across multiple SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Building on our work from &lt;a href="https://pubnub.com/docs/release-notes/2025/may#java-sdk-with-github-sourced-code-examples" rel="noopener noreferrer"&gt;previous months&lt;/a&gt;, we rolled out updated code snippets for multiple SDKs. All examples are pulled directly from our GitHub repositories, so they're always fresh and proven to work.&lt;/p&gt;

&lt;p&gt;This month's updated SDKs include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/swift" rel="noopener noreferrer"&gt;&lt;strong&gt;Swift SDK&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/c-sharp" rel="noopener noreferrer"&gt;&lt;strong&gt;C# SDK&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/javascript" rel="noopener noreferrer"&gt;&lt;strong&gt;JavaScript SDK&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These updated snippets sync automatically with our SDK repositories, so you always get tested, working code examples that match the latest SDK versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continued Getting Started guide improvements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We kept up our &lt;a href="https://pubnub.com/docs/release-notes/2025/april#updated-getting-started-guides-for-multiple-sdks" rel="noopener noreferrer"&gt;systematic approach&lt;/a&gt; to Getting Started guides with updates for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://pubnub.com/docs/sdks/rust" rel="noopener noreferrer"&gt;Rust SDK&lt;/a&gt;&lt;/strong&gt;: Complete Getting Started guide following our standardized format&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://pubnub.com/docs/sdks/javascript" rel="noopener noreferrer"&gt;JavaScript SDK&lt;/a&gt;&lt;/strong&gt;: Refined and updated Getting Started experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both guides follow our established pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Setup and installation&lt;/li&gt;
&lt;li&gt; Creating a PubNub instance with your keys&lt;/li&gt;
&lt;li&gt; Subscribing to channels&lt;/li&gt;
&lt;li&gt; Publishing messages&lt;/li&gt;
&lt;li&gt; Handling received messages&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This ensures consistent onboarding across all our SDKs, no matter which programming language you prefer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced Chat SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Chat SDK documentation expanded to support Platform Support pages (similar to those available in the &lt;a href="https://www.pubnub.com/docs/sdks?" rel="noopener noreferrer"&gt;Core SDKs&lt;/a&gt;) and improved capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Unreal Chat SDK&lt;/strong&gt;: Added comprehensive documentation for the event engine, enabling more sophisticated event handling in Unreal Engine applications&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Kotlin Chat SDK&lt;/strong&gt;: Enhanced documentation with additional features and better examples for Android development&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Platform support documentation&lt;/strong&gt;: Updated general platform support information across all Chat SDKs (&lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/platform-support" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk/build/platform-support" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/platform-support" rel="noopener noreferrer"&gt;Swift&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/unity-chat-sdk/build/platform-support" rel="noopener noreferrer"&gt;Unity&lt;/a&gt;, and &lt;a href="https://pubnub.com/docs/chat/unreal-chat-sdk/build/platform-support" rel="noopener noreferrer"&gt;Unreal&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These improvements make integrating chat functionality into games and applications much easier, with better support for platform-specific features.&lt;/p&gt;

&lt;h3&gt;
  
  
  SDK-specific troubleshooting documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We added troubleshooting guides for specific SDKs to tackle common development challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://pubnub.com/docs/sdks/kotlin/troubleshoot" rel="noopener noreferrer"&gt;Kotlin SDK&lt;/a&gt;&lt;/strong&gt;: Added ProGuard configuration troubleshooting for common Android build issues&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://pubnub.com/docs/sdks/unity/troubleshoot" rel="noopener noreferrer"&gt;Unity SDK&lt;/a&gt;&lt;/strong&gt;: Updated mobile build configuration guidance for Android and iOS deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These guides provide step-by-step solutions for SDK-specific configuration issues and platform challenges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved Presence configuration documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pubnub.com/docs/general/presence/overview" rel="noopener noreferrer"&gt;Presence documentation&lt;/a&gt; got clearer with better guidance on configuration and event handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Custom Presence events&lt;/strong&gt;: Updated terminology from "custom Presence event" to "&lt;a href="https://pubnub.com/docs/general/presence/presence-events" rel="noopener noreferrer"&gt;state change event&lt;/a&gt;" for clarity across all SDK documentation&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Default Presence configuration&lt;/strong&gt;: Better explanations of default Presence settings and how to customize them, including updates to &lt;a href="https://pubnub.com/docs/bizops-workspace/presence-management" rel="noopener noreferrer"&gt;BizOps Workspace Presence Management&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These improvements help you understand and implement Presence features more easily, with clearer explanations of when and how Presence events are triggered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other 🌟
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sports, Media &amp;amp; Entertainment documentation organization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We launched a comprehensive new &lt;a href="https://pubnub.com/docs/entertainment" rel="noopener noreferrer"&gt;Sports, Media &amp;amp; Entertainment documentation section&lt;/a&gt; with industry-specific guidance and real-world examples.&lt;/p&gt;

&lt;p&gt;This new documentation includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Interactive demo&lt;/strong&gt;: A &lt;a href="https://pn-solution-live-events.netlify.app/" rel="noopener noreferrer"&gt;live demonstration&lt;/a&gt; showcasing real-time sports experiences with synchronized stats, live chat, and fan engagement features&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Industry-specific use cases&lt;/strong&gt;: Tailored examples for sports scoring, media streaming, and entertainment platforms&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Best practices&lt;/strong&gt;: Implementation guidance for common sports and entertainment scenarios&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Real-time features&lt;/strong&gt;: Documentation for live polls, score predictions, commentary synchronization, and fan behavior management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This focused content helps developers in the Sports, Media &amp;amp; Entertainment industry find relevant examples and implementation guides quickly, with content designed specifically for real-time sports updates, media streaming, and entertainment platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Homepage enhancements with "What's New" badge
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We added a "What's New" badge system to our homepage and release notes overview page. This makes it much easier to spot recent updates and new features across PubNub documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftudj88nny29nyuqk6cis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftudj88nny29nyuqk6cis.png" alt="What's New" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The badge system highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  New features and major updates&lt;/li&gt;
&lt;li&gt;  Recently updated SDK documentation&lt;/li&gt;
&lt;li&gt;  Important announcements and changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can stay current with PubNub's latest developments and won't miss important updates that might affect your applications.&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Documentation Release Notes - May 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Tue, 17 Jun 2025 08:54:28 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-may-2025-2g24</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-may-2025-2g24</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/may?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/may&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This May, we focused on making our documentation more practical and easier to use across different SDKs and platforms.&lt;/p&gt;

&lt;p&gt;We continued our work on Getting Started guides and basic usage examples that we started in previous months. Our Functions documentation got a refresh with better organization between v1 and v2, plus clearer explanations of wildcard patterns. We also added documentation for our new PubNub MCP Server, which lets AI IDEs, like Cursor or Windsurf, work directly with your PubNub apps.&lt;/p&gt;

&lt;p&gt;On the SDK side, we improved Objective-C documentation with better examples and updated our Java docs to use code examples straight from our GitHub repos.&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New PubNub MCP Server documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've added documentation for the &lt;a href="https://pubnub.com/docs/general/setup/pubnub-mcp-server" rel="noopener noreferrer"&gt;PubNub MCP Server&lt;/a&gt;, a new tool that lets AI tools interact directly with your PubNub applications through the Model Context Protocol (MCP).&lt;/p&gt;

&lt;p&gt;With this integration, AI assistants can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Publish messages to channels&lt;/li&gt;
&lt;li&gt;  Subscribe to channels and get real-time updates&lt;/li&gt;
&lt;li&gt;  Pull message history&lt;/li&gt;
&lt;li&gt;  Handle user presence&lt;/li&gt;
&lt;li&gt;  Work with channel groups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The MCP Server bridges AI assistants and PubNub's real-time network, opening up new possibilities for AI-powered apps and automated workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  MQTT documentation removed
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Adjustment&lt;/p&gt;

&lt;p&gt;We've removed MQTT documentation from our docs as this integration is no longer actively supported. This cleanup keeps our documentation focused on actively maintained SDKs and integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions ⚙️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Better Functions v2 documentation with wildcard support
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've improved our &lt;a href="https://pubnub.com/docs/serverless/functions/overview" rel="noopener noreferrer"&gt;Functions documentation&lt;/a&gt; with better organization between Functions v1 and v2.&lt;/p&gt;

&lt;p&gt;Here's what's new:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Wildcard pattern explanations&lt;/strong&gt;: Clear documentation on using wildcard patterns in channel names and event triggers&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Better v1 vs v2 separation&lt;/strong&gt;: Organized docs to help you understand which version you're using and what features are available&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Improved migration guidance&lt;/strong&gt;: Better information for moving from Functions v1 to v2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These updates make it easier to use Functions v2 features like advanced pattern matching and flexible event handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Better Objective-C SDK documentation and examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Continuing our work from previous months on basic usage examples, we've updated the &lt;a href="https://pubnub.com/docs/sdks/objective-c" rel="noopener noreferrer"&gt;Objective-C SDK documentation&lt;/a&gt; with practical, ready-to-use examples throughout the API reference.&lt;/p&gt;

&lt;p&gt;What's included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Complete basic usage examples for all major features&lt;/li&gt;
&lt;li&gt;  Better code samples for publish/subscribe operations&lt;/li&gt;
&lt;li&gt;  Improved documentation for Access Manager, channel groups, and presence features&lt;/li&gt;
&lt;li&gt;  Clearer examples for file handling and message actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now Objective-C developers have working examples for all PubNub features, making integration faster and more straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Java SDK with GitHub-sourced code examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our Java SDK documentation to use code examples pulled directly from our &lt;a href="https://github.com/pubnub/java" rel="noopener noreferrer"&gt;GitHub repositories&lt;/a&gt;. This ensures all examples are tested and current with the latest SDK versions.&lt;/p&gt;

&lt;p&gt;This approach means the code examples in our docs always reflect working, tested implementations, so you won't run into outdated or broken code snippets.&lt;/p&gt;

&lt;h3&gt;
  
  
  More Getting Started guide improvements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Building on our April work to standardize Getting Started guides, we've continued refining the &lt;a href="https://pubnub.com/docs/sdks/swift" rel="noopener noreferrer"&gt;Swift SDK Getting Started guide&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/sdks/unity" rel="noopener noreferrer"&gt;Unity SDK basic usage examples&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These updates ensure consistent onboarding across all our SDKs, following the same clear pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Setup and installation&lt;/li&gt;
&lt;li&gt; Creating a PubNub instance with your keys&lt;/li&gt;
&lt;li&gt; Subscribing to channels&lt;/li&gt;
&lt;li&gt; Publishing messages&lt;/li&gt;
&lt;li&gt; Handling received messages&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  JavaScript Chat SDK method rename
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated the JavaScript Chat SDK documentation to reflect the renaming of &lt;code&gt;getUnreadMessagesCounts()&lt;/code&gt; to &lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/features/messages/unread#get-unread-messages-count-all-channels" rel="noopener noreferrer"&gt;&lt;code&gt;fetchUnreadMessagesCounts()&lt;/code&gt;&lt;/a&gt; for better consistency.&lt;/p&gt;

&lt;p&gt;The new method also returns a more structured response with &lt;code&gt;countsByChannel&lt;/code&gt; array and pagination information.&lt;/p&gt;

&lt;p&gt;The previous method remains available but is now deprecated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other 🌟
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Site experience improvements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've made several improvements to the documentation site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Mobile menu fixes&lt;/strong&gt;: Fixed navigation issues on mobile devices for better accessibility&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Search improvements&lt;/strong&gt;: Made the search feature more accurate and relevant&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Interface polish&lt;/strong&gt;: Various small improvements to tooltips and navigation elements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These updates make browsing our documentation smoother across all devices and platforms.&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Documentation Release Notes - April 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Thu, 15 May 2025 14:02:00 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-april-2025-1d3d</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-april-2025-1d3d</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/april?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/april&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This April, we've focused on making our documentation more practical and easier to use.&lt;/p&gt;

&lt;p&gt;We've updated Getting Started guides for multiple SDKs to provide clearer onboarding paths, added comprehensive documentation for status events across our C-Core, Rust, JavaScript and other SDKs, and improved support for custom events and event listeners.&lt;/p&gt;

&lt;p&gt;Plus, we've enhanced our REST API documentation with better SEO-optimized titles and links, making it easier for you to find the information you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Improved REST API documentation titles &amp;amp; links for SEO
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've made significant improvements to our &lt;a href="https://pubnub.com/docs/sdks/rest-api" rel="noopener noreferrer"&gt;REST API documentation&lt;/a&gt; titles and internal links to enhance searchability and make it easier for you to find the information you need.&lt;/p&gt;

&lt;p&gt;These updates include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  More descriptive page titles that better reflect the content&lt;/li&gt;
&lt;li&gt;  Optimized keywords in documentation headings&lt;/li&gt;
&lt;li&gt;  Improved cross-linking between related API endpoints&lt;/li&gt;
&lt;li&gt;  Clearer navigation paths throughout the REST API documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This work ensures that whether you're searching on our site or through external search engines, you'll find the relevant REST API documentation more quickly and intuitively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updated App Context optional fields in REST API docs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our &lt;a href="https://pubnub.com/docs/sdks/rest-api/get-metadata-for-all-users" rel="noopener noreferrer"&gt;REST API documentation&lt;/a&gt; to clarify which fields are optional when working with App Context. This update provides better guidance on the minimum required parameters for various operations, making it easier to work with our APIs without including unnecessary data.&lt;/p&gt;

&lt;p&gt;The documentation now clearly indicates which fields can be omitted in your API requests, helping you create more concise and efficient API calls when working with channels, users, and memberships through the REST API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updated MAU limit information
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Adjustment&lt;/p&gt;

&lt;p&gt;We've updated the documentation regarding &lt;a href="https://pubnub.com/docs/general/setup/account-setup#pricing-model" rel="noopener noreferrer"&gt;Monthly Active User (MAU)&lt;/a&gt; limits to provide clearer guidance on the maximum number of users that can authenticate simultaneously on a single device.&lt;/p&gt;

&lt;p&gt;This information is critical for developers building applications where multiple users might share the same device, ensuring you can plan your architecture appropriately within our platform's constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Improved status event documentation across SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've added detailed documentation for status events across multiple SDKs to help you better understand and handle various connection states and error conditions. This documentation is now available for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/c-core/status-events" rel="noopener noreferrer"&gt;C-Core SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/javascript/status-events" rel="noopener noreferrer"&gt;JavaScript SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/swift/status-events" rel="noopener noreferrer"&gt;Swift SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/rust/status-events" rel="noopener noreferrer"&gt;Rust SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/python/status-events" rel="noopener noreferrer"&gt;Python SDK&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each SDK's documentation now includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Visual flowcharts showing possible connection states&lt;/li&gt;
&lt;li&gt;  Detailed descriptions of each status type&lt;/li&gt;
&lt;li&gt;  When each status was introduced or changed&lt;/li&gt;
&lt;li&gt;  Code examples showing how to properly handle status events&lt;/li&gt;
&lt;li&gt;  Error categorization to help with troubleshooting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This enhancement makes it much easier to build reliable applications that gracefully handle network issues, reconnection scenarios, and various error conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subscribe loop and Event Listeners updates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our documentation for event handling across multiple SDKs, with a particular focus on the new standardized subscribe loop architecture. This update covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Standardized event listeners for message, signal, presence, and file events in JavaScript, Swift, Rust, and C-Core SDKs&lt;/li&gt;
&lt;li&gt;  Custom event payloads for app-specific events in Chat SDKs (JavaScript, Kotlin, Swift, Unreal)&lt;/li&gt;
&lt;li&gt;  Improved error handling and event type discrimination in subscription status events&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Updated Getting Started guides for multiple SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've completely revamped the Getting Started guides for multiple SDKs to provide a more consistent, user-friendly experience across our documentation. The updated guides include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Platform-specific installation instructions&lt;/li&gt;
&lt;li&gt;  Complete, copy-paste ready code examples&lt;/li&gt;
&lt;li&gt;  Clear step-by-step progression&lt;/li&gt;
&lt;li&gt;  Required keyset configuration information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following SDKs now have enhanced Getting Started guides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/php" rel="noopener noreferrer"&gt;PHP SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/go" rel="noopener noreferrer"&gt;Go SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/swift" rel="noopener noreferrer"&gt;Swift SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/ruby" rel="noopener noreferrer"&gt;Ruby SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/unity" rel="noopener noreferrer"&gt;Unity SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/c-sharp" rel="noopener noreferrer"&gt;C# SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/dart" rel="noopener noreferrer"&gt;Dart SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/python" rel="noopener noreferrer"&gt;Python SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/asyncio" rel="noopener noreferrer"&gt;Asyncio SDK&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each guide now follows a consistent pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Setup and installation&lt;/li&gt;
&lt;li&gt; Creating a PubNub instance with your keys&lt;/li&gt;
&lt;li&gt; Subscribing to channels&lt;/li&gt;
&lt;li&gt; Publishing messages&lt;/li&gt;
&lt;li&gt; Handling received messages&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This standardized approach makes it easier to get started with any PubNub SDK, regardless of your preferred programming language or platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Membership type and status in Unreal and Unreal Chat SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our documentation for the &lt;a href="https://pubnub.com/docs/sdks/unreal" rel="noopener noreferrer"&gt;Unreal SDK&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/chat/unreal-chat-sdk" rel="noopener noreferrer"&gt;Unreal Chat SDK&lt;/a&gt; to better support membership type and status fields in user-channel relationships. These updates include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Added support for &lt;code&gt;Type&lt;/code&gt; and &lt;code&gt;Status&lt;/code&gt; fields in memberships&lt;/li&gt;
&lt;li&gt;  Improved documentation on how to use membership types for role-based access&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enhanced examples showing proper membership management&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unreal Chat SDK&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unreal SDK&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kismet/GameplayStatics.h&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PubnubChatSubsystem.h&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;UGameInstance&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;GameInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UGameplayStatics&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;GetGameInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;UPubnubChatSubsystem&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;PubnubChatSubsystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GameInstance&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;GetSubsystem&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UPubnubChatSubsystem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;UPubnubChat&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;Chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PubnubChatSubsystem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;InitChat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my_user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get an existing user&lt;/span&gt;
&lt;span class="nx"&gt;UPubnubUser&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Chat&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;support_agent_15&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Find memberships for a specific channel&lt;/span&gt;
&lt;span class="nx"&gt;FString&lt;/span&gt; &lt;span class="nx"&gt;Filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;channel.id == 'high-priority-incidents'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;FPubnubMembershipsResponseWrapper&lt;/span&gt; &lt;span class="nx"&gt;Memberships&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;GetMemberships&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kismet/GameplayStatics.h&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;include&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PubnubSubsystem.h&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;AMyActor&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;GetMemberships&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;UGameInstance&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;GameInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UGameplayStatics&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;GetGameInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;UPubnubSubsystem&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;PubnubSubsystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GameInstance&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;GetSubsystem&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UPubnubSubsystem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;FString&lt;/span&gt; &lt;span class="nx"&gt;UserID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agent-123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// UserID needs to be set for any Pubnub Operations&lt;/span&gt;
    &lt;span class="nx"&gt;PubnubSubsystem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;SetUserID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Bind response delegate&lt;/span&gt;
    &lt;span class="nx"&gt;FOnGetMembershipsResponse&lt;/span&gt; &lt;span class="nx"&gt;OnGetMembershipResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Type&lt;/code&gt; field supports categorizing memberships (such as "moderator", "admin", "guest"), while the &lt;code&gt;Status&lt;/code&gt; field helps track membership states (like "active", "pending", "blocked"). These fields make it easier to implement role-based permissions and track user engagement in your Unreal applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other 🌟
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Table tooltips improvement
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've improved the tooltip functionality in our documentation tables to provide clearer, more contextual information when hovering over table elements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpyi76mbgtv7poo8jyfy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpyi76mbgtv7poo8jyfy0.png" alt="Tooltips in tables" width="800" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The improved tooltips now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Appear with a blurred, centered background that ensures full visibility&lt;/li&gt;
&lt;li&gt;  Remain completely visible regardless of their position in the table&lt;/li&gt;
&lt;li&gt;  No longer get cut off at table edges or when near page boundaries&lt;/li&gt;
&lt;li&gt;  Provide clearer visual distinction between the tooltip and the underlying content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll find these enhanced tooltips throughout our API reference tables, making it easier to understand the available options at a glance.&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Documentation Release Notes - March 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Wed, 09 Apr 2025 09:52:24 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-march-2025-pmb</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-march-2025-pmb</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/march?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/march&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This March, we've focused on enhancing both functionality and usability across our documentation.&lt;/p&gt;

&lt;p&gt;Security gets a boost with our new secret key rotation feature, while developers will appreciate the async/await patterns in our Swift Chat SDK and improved table layouts for API references.&lt;/p&gt;

&lt;p&gt;We've also documented adding practical tools like customizable table settings in BizOps Workspace and more granular control over action execution in Illuminate.&lt;/p&gt;

&lt;p&gt;Take a look at what's new!&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Optimized filtering for large data volumes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;This month, we improved our documentation to help you work with large volumes of data more efficiently. If your application has thousands of channels or users, you'll now find helpful performance tips throughout our docs.&lt;/p&gt;

&lt;p&gt;We added guidance on optimal filtering methods in the BizOps Workspace, recommending the use of exact ID equality filters instead of pattern matching when searching through applications with many channels or users.&lt;/p&gt;

&lt;p&gt;You can find these recommendations in the &lt;a href="https://pubnub.com/docs/bizops-workspace/channel-management#create-channels" rel="noopener noreferrer"&gt;Channel Management&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/bizops-workspace/user-management#create-users" rel="noopener noreferrer"&gt;User Management&lt;/a&gt;, and general &lt;a href="https://pubnub.com/docs/general/metadata/filtering#filtering-operators" rel="noopener noreferrer"&gt;Filtering&lt;/a&gt; documentation sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Admin Portal navigation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've recently refreshed our &lt;a href="https://admin.pubnub.com?" rel="noopener noreferrer"&gt;Admin Portal&lt;/a&gt;'s left navigation and updated all the documentation resources to match it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21lg4jvgghms1y2ppzw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21lg4jvgghms1y2ppzw0.png" alt="New Portal navigation" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Apps&lt;/strong&gt; section has also been renamed to &lt;strong&gt;Apps &amp;amp; Keysets&lt;/strong&gt;, bringing keyset management right where you need it instead of in a separate section.&lt;/p&gt;

&lt;p&gt;All screenshots throughout our docs now reflect these changes, so what you see in the docs matches exactly what you'll find in the Portal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secret key rotation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've added a new security feature for our paid plans: &lt;a href="https://pubnub.com/docs/general/portal/keysets#secret-key-rotation" rel="noopener noreferrer"&gt;secret key rotation&lt;/a&gt;. This enhancement lets you manage up to five secret keys with automatic expiration dates, strengthening your security when using services like Access Manager.&lt;/p&gt;

&lt;p&gt;You'll find this feature in the Admin Portal under your keyset settings, where you can easily set expiration dates for your secret keys using our new date picker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdumqhqnmxza0h5jm4jw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdumqhqnmxza0h5jm4jw.png" alt="Secret key rotation" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Improved metadata for Objective-C SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've updated our &lt;a href="https://pubnub.com/docs/sdks/objective-c/api-reference/objects" rel="noopener noreferrer"&gt;Objective-C SDK&lt;/a&gt; docs with new features that give you better control over your data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Added &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; fields for users, channels, and memberships so you can better organize and track their states.&lt;/li&gt;
&lt;li&gt;  Implemented &lt;code&gt;ifMatchesEtag&lt;/code&gt; support to prevent update conflicts when multiple systems try to change the same data.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;NSArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NSDictionary&lt;/span&gt; &lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;channels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;@[&lt;/span&gt;
  &lt;span class="p"&gt;@{&lt;/span&gt; 
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;channel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;channel1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;custom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@{&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moderator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;PNSetMembershipsRequest&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PNSetMembershipsRequest&lt;/span&gt; &lt;span class="nx"&gt;requestWithUUID&lt;/span&gt;&lt;span class="p"&gt;:@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uuid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                                                                   &lt;span class="nx"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="nx"&gt;setMembershipsWithRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt; 
                          &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PNSetMembershipsStatus&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle completion&lt;/span&gt;
&lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom origin arrays in JavaScript SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/configuration#initialization" rel="noopener noreferrer"&gt;JavaScript SDK&lt;/a&gt; documentation to show that you can use an array of strings for the &lt;code&gt;origin&lt;/code&gt; configuration parameter, giving you more flexibility in how you connect to PubNub.&lt;/p&gt;

&lt;p&gt;Previously, the &lt;code&gt;origin&lt;/code&gt; parameter only accepted a single string value, but now you can provide multiple origin domains as an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// Other config options...&lt;/span&gt;
  &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ps1.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ps2.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enhancement is useful for implementing your own failover strategy or connecting to multiple custom domains.&lt;/p&gt;

&lt;h3&gt;
  
  
  New C# logging system
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our &lt;a href="https://pubnub.com/docs/sdks/c-sharp/troubleshooting" rel="noopener noreferrer"&gt;C# SDK&lt;/a&gt; docs with a completely revamped logging system. The key improvements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;New logging interface&lt;/strong&gt;: Replaced the deprecated &lt;code&gt;PubnubLog&lt;/code&gt; and &lt;code&gt;LogVerbosity&lt;/code&gt; with a new &lt;code&gt;LogLevel&lt;/code&gt; parameter and &lt;code&gt;IPubnubLogger&lt;/code&gt; interface.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Multiple severity levels&lt;/strong&gt;: Added granular log levels (&lt;code&gt;Trace&lt;/code&gt;, &lt;code&gt;Debug&lt;/code&gt;, &lt;code&gt;Info&lt;/code&gt;, &lt;code&gt;Warn&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;) replacing the previous simple verbosity options.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Custom logger support&lt;/strong&gt;: Added a new &lt;code&gt;SetLogger&lt;/code&gt; method allowing developers to implement and attach their own logger implementations.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Better error handling examples&lt;/strong&gt;: Updated all code examples to use try/catch blocks and proper async/await patterns.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Request execution guide&lt;/strong&gt;: Added a new partial template explaining best practices for executing API requests with proper error handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The docs also include a complete sample implementation of a console logger and shows how to properly configure and remove loggers.&lt;/p&gt;

&lt;p&gt;This update makes debugging and troubleshooting C# applications much more powerful and flexible.&lt;/p&gt;

&lt;h3&gt;
  
  
  ETag support in Dart SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've added ETag support to our Dart SDK, making your apps safer when multiple users might update the same data at once.&lt;/p&gt;

&lt;p&gt;When you set metadata for users or channels, you can now include an &lt;code&gt;ifMatchesEtag&lt;/code&gt; parameter. This works like a safety check - it ensures your updates only happen if no one else has changed the data since you last retrieved it.&lt;/p&gt;

&lt;p&gt;For example, if two people try to edit a user profile at the same time, ETags help prevent one person's changes from accidentally overwriting the other's.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pubnub.com/docs/sdks/dart/api-reference/objects#set-user-metadata" rel="noopener noreferrer"&gt;Dart SDK docs&lt;/a&gt; now include this parameter in both the UUID and channel metadata methods, showing how to use it in your Dart apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// First, retrieve user metadata which includes the ETag&lt;/span&gt;
&lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUUIDMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;includeCustomFields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Store the ETag from the response&lt;/span&gt;
&lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;etag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;eTag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Update user metadata with ETag to prevent conflicts&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;etag&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setUUIDMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Updated Username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Invites now supported in public chats
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our Chat SDK documentation to remove the limitation that previously stated invites weren't supported in public channels. This change affects all our Chat SDK platforms including &lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/features/channels/create#create-public-channel" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/create#create-public-channel" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/features/channels/create#create-public-channel" rel="noopener noreferrer"&gt;Swift&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/create#create-public-channel" rel="noopener noreferrer"&gt;Unity&lt;/a&gt;, and &lt;a href="https://pubnub.com/docs/chat/unreal-chat-sdk/build/features/channels/create#create-public-channel" rel="noopener noreferrer"&gt;Unreal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Previously, our docs warned that invitation features were disabled in public chats, and attempting to use them would trigger an error message. We've now removed these warnings as implementation has changed, meaning you can now invite users to public channels just like you would with private or group conversations.&lt;/p&gt;

&lt;p&gt;This update in Chat SDKs gives you more flexibility in how you manage user access to your public chat spaces, allowing for a more consistent invitation experience across all channel types in your chat applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comprehensive Access Manager docs for Chat SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've added &lt;a href="https://pubnub.com/docs/chat/security#operations-to-permissions-mapping" rel="noopener noreferrer"&gt;detailed security documentation&lt;/a&gt; for our Chat SDKs to help you correctly set up permissions in your chat apps.&lt;/p&gt;

&lt;p&gt;The update provides a clear mapping between Chat SDK methods and the specific &lt;a href="https://pubnub.com/docs/general/security/access-control" rel="noopener noreferrer"&gt;Access Manager&lt;/a&gt; permissions they require.&lt;/p&gt;

&lt;p&gt;The updated &lt;strong&gt;Security and permissions&lt;/strong&gt; page now includes comprehensive tables showing exactly which permissions are needed for every method across all Chat SDK objects - Chat, Channel, User, Membership, Message, ThreadChannel, ThreadMessage, and MessageDraft.&lt;/p&gt;

&lt;p&gt;For example, you can now easily see that to use the &lt;code&gt;SendText()&lt;/code&gt; method, your users need &lt;code&gt;Write&lt;/code&gt; permission on the channel, or that creating a direct conversation requires multiple permissions including &lt;code&gt;Get&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Join&lt;/code&gt;, and &lt;code&gt;Write&lt;/code&gt; on specific resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  PHP SDK transport layer improvement
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;The PHP SDK has been updated with a major change to how it handles HTTP requests. We've added a detailed &lt;a href="https://pubnub.com/docs/general/resources/migration-guides/php-8.0.0-migration-guide" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt; to help you update your code from version 7.x to 8.x.&lt;/p&gt;

&lt;p&gt;The key changes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Replacing the outdated custom transport layer with a standardized PSR-18 compliant implementation.&lt;/li&gt;
&lt;li&gt;  Using Guzzle HTTP client as the default, which provides better performance and compatibility.&lt;/li&gt;
&lt;li&gt;  Changing the method to customize HTTP handling from &lt;code&gt;setTransport()&lt;/code&gt; to &lt;code&gt;setClient()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're using the default transport layer, you won't need to make any changes to your code. However, if you've implemented a custom transport, you'll need to update it to follow PSR-18 standards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Swift Chat SDK now supports async/await
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We've updated our &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk" rel="noopener noreferrer"&gt;Swift Chat SDK&lt;/a&gt; documentation to use Swift's newer async/await feature, making your code much simpler to write and read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  No more nested callbacks or complex error handling chains.&lt;/li&gt;
&lt;li&gt;  Use try/catch instead of managing result types.&lt;/li&gt;
&lt;li&gt;  Code that reads more naturally from top to bottom.&lt;/li&gt;
&lt;li&gt;  Aligns with how most Swift developers write code today.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;support&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timetoken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;shouldStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message sent at &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;(timetoken)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This update affects all our Swift code examples throughout the docs. While you can still use the older completion handler style if you prefer, we believe you'll find this new approach much easier to work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retired SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Deprecation&lt;/p&gt;

&lt;p&gt;We've updated our documentation to mark four SDKs as no longer officially supported: &lt;a href="https://pubnub.com/docs/sdks/lua" rel="noopener noreferrer"&gt;Lua&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/sdks/redux" rel="noopener noreferrer"&gt;Redux&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/sdks/cocoa-swift" rel="noopener noreferrer"&gt;Cocoa Swift&lt;/a&gt;, and &lt;a href="https://pubnub.com/docs/sdks/cocoa-objective-c" rel="noopener noreferrer"&gt;Cocoa Objective-C&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead of removing them completely, we're inviting you to take them forward.&lt;/p&gt;

&lt;p&gt;Each SDK page now includes a clear warning banner explaining that PubNub no longer maintains these SDKs, but also provides a direct link to their related GitHub repositories where you can contribute improvements and fixes. We've also updated our main SDKs list page and navigation to reflect these changes.&lt;/p&gt;

&lt;p&gt;While we're focusing our resources on our most widely-used SDKs, we understand that you may still be using these technologies and want to provide a path for community-driven support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved Basic Usage examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Improvement&lt;/p&gt;

&lt;p&gt;We've updated the first &lt;strong&gt;Basic Usage&lt;/strong&gt; example in each documentation page across multiple SDKs to make them truly copy-paste ready. These changes have been made to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/unreal/api-reference/publish-and-subscribe#basic-usage" rel="noopener noreferrer"&gt;Unreal SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/swift/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;Swift SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/ruby/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;Ruby SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/c-sharp/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;C# SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/dart/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;Dart SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/go/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;Go SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/java/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;Java SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;JavaScript SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pubnub.com/docs/sdks/kotlin/api-reference/configuration#basic-usage" rel="noopener noreferrer"&gt;Kotlin SDK&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These updated first examples now include everything you need: all necessary imports, variable declarations, proper error handling, and complete context.&lt;/p&gt;

&lt;p&gt;While other examples in the documentation may still focus just on the PubNub-specific code, these first examples serve as complete templates you can use to understand how to properly set up and use the SDK in your projects. This makes it easier to get started and provides a reference point for implementing the other examples shown later in the documentation.&lt;/p&gt;

&lt;p&gt;More to come!&lt;/p&gt;

&lt;h3&gt;
  
  
  Redesigned Getting Started guide for Kotlin SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Improvement&lt;/p&gt;

&lt;p&gt;We've completely redesigned the &lt;a href="https://pubnub.com/docs/sdks/kotlin" rel="noopener noreferrer"&gt;Getting Started guide&lt;/a&gt; for our Kotlin SDK to make it more user-friendly and practical. This update is part of our broader effort to improve all SDK documentation with comprehensive, copy-paste ready code examples.&lt;/p&gt;

&lt;p&gt;The new guide features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Platform-specific guidance&lt;/li&gt;
&lt;li&gt;  Complete working examples&lt;/li&gt;
&lt;li&gt;  Clear step-by-step structure with a logical progression from setup to publishing and subscribing to messages&lt;/li&gt;
&lt;li&gt;  Added tooltips for key terms and better organized sections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've also simplified the overall structure to remove repetition and focus on what developers actually need. The guide now follows a practical flow: get your keys, install the SDK, initialize PubNub, subscribe to messages, and publish messages - with complete code examples at each step.&lt;/p&gt;

&lt;p&gt;This new template will serve as a model for updating other SDK Getting Started guides, ensuring a consistent, easy-to-follow experience across our entire SDK docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insights 📊
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Channel patterns in PubNub Insights API
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We've added API documentation for the &lt;a href="https://pubnub.com/docs/pubnub-insights/api" rel="noopener noreferrer"&gt;channel patterns&lt;/a&gt; feature in PubNub Insights.&lt;/p&gt;

&lt;p&gt;Premium customers can now programmatically filter and retrieve analytics data for specific channel patterns using the Insights API, making it easier to analyze targeted subsets of channels in their applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  BizOps Workspace 🏢
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Customizable table settings in Channel and User Management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pubnub.com/docs/bizops-workspace/channel-management#create-channels" rel="noopener noreferrer"&gt;Channel Management&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/bizops-workspace/user-management#create-users" rel="noopener noreferrer"&gt;User Management&lt;/a&gt; sections under BizOps Workspace have been enhanced by adding table settings to each view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo766v383k8gp4phk3hw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo766v383k8gp4phk3hw.png" alt="Table settings - icon" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This option lets you adjust the way tables display information.&lt;/p&gt;

&lt;p&gt;Table settings include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Columns tab: Toggle visibility for &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Status&lt;/code&gt;, &lt;code&gt;Type&lt;/code&gt;, and &lt;code&gt;Updated&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Row height tab for selecting relaxed, regular, and condensed row view.&lt;/li&gt;
&lt;li&gt;  Column management: Pinning (pin icon) and reordering (up/down arrows).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkrmrxquglaogzrj0xce3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkrmrxquglaogzrj0xce3.png" alt="Table settings - details" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  File upload in Channel Monitor
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We added documentation for a new &lt;a href="https://pubnub.com/docs/bizops-workspace/channel-monitor#upload-files" rel="noopener noreferrer"&gt;file upload&lt;/a&gt; feature in the Channel Monitor tool within BizOps Workspace.&lt;/p&gt;

&lt;p&gt;This enhancement allows moderators to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  View files uploaded by chat members in messages.&lt;/li&gt;
&lt;li&gt;  Upload their own files to messages.&lt;/li&gt;
&lt;li&gt;  Work with files regardless of which SDK (Core or Chat) the app is built with.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Illuminate 💡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Action execution interval
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We added a new feature to Illuminate Decisions that lets you control how often actions run.&lt;/p&gt;

&lt;p&gt;Instead of triggering actions every single time conditions are met, you can now &lt;a href="https://pubnub.com/docs/illuminate/decisions/basics#action-execution-limit" rel="noopener noreferrer"&gt;set limits&lt;/a&gt;. You can choose to run actions always, just once within a time period, or once per unique condition value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd81vxcrsy4kccibb1sq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd81vxcrsy4kccibb1sq2.png" alt="Action execution options" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need to start fresh, you can reset these limits with a button click without turning off the whole decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15d2sa02fllgqh8nsh7e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15d2sa02fllgqh8nsh7e.png" alt="Action execution limit reset" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other 🌟
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Improved table layout
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We redesigned how tables display in our documentation to improve readability, especially for API references.&lt;/p&gt;

&lt;p&gt;Instead of showing all columns side-by-side requiring horizontal scrolling, we now present essential information prominently while moving supporting details into a compact format below the parameter name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs5xm0gdw8eg5zx0ga6qu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs5xm0gdw8eg5zx0ga6qu.png" alt="New table layout" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Required parameters are clearly marked with red asterisks, and the responsive design automatically adjusts to different screen sizes for better viewing on all devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  New tab navigation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Last but not least, we redesigned our documentation tabs with a more intuitive and visually appealing interface following user feedback that the previous design wasn't clearly recognizable as interactive tabs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnri2z8irlbn6dff23y4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnri2z8irlbn6dff23y4.png" alt="Improved tab navigation" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The new tab components feature clear visual indicators for active tabs with a modern blue highlight and subtle hover effects for better interactivity. Tabs now include a clean divider line that clearly separates the tab navigation from content.&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Documentation Release Notes - February 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Mon, 17 Mar 2025 10:19:24 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-february-2025-42cl</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-february-2025-42cl</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/february?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/february&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the year is getting underway, we've been busy not only enhancing the existing docs based on your feedback but also adding a bunch of new updates following new product releases.&lt;/p&gt;

&lt;p&gt;Here’s a sneak peek:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Admin Portal&lt;/strong&gt; – We've introduced secret management and launched a public demo, so you can explore PubNub features without needing an account.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;SDKs&lt;/strong&gt; – Added membership type support for Python and PHP SDKs along with eTag support across more SDKs for greater data consistency.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Events &amp;amp; Actions&lt;/strong&gt; – You can now use vault secrets in webhook headers, boosting your app's security.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;BizOps Workspace&lt;/strong&gt; – The UI got a facelift with clearly marked read-only internal objects for better navigation.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Illuminate&lt;/strong&gt; – We’ve expanded your ability to view action history, removing previous limits for easier tracking.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Miscellaneous&lt;/strong&gt; – We addressed several feedback tickets, enriching our docs with new examples and clarifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scroll down to dive into all the updates and see what’s new and improved.&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Secret management in the Admin Portal
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Apps &amp;amp; Keysets&lt;/strong&gt; section in the Admin Portal now has a new &lt;a href="https://pubnub.com/docs/general/portal/keysets#manage-secrets" rel="noopener noreferrer"&gt;&lt;strong&gt;Manage secrets&lt;/strong&gt;&lt;/a&gt; section that allows users with the Keyset Admin, Account Owner, and Account Admin roles to create, update, and delete secrets.&lt;/p&gt;

&lt;p&gt;You can use these secrets in Functions to authenticate and secure connection with third-party services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggqti3ehbkach1pni8x7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggqti3ehbkach1pni8x7.png" alt="Secret management" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Admin Portal demo
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;Want to browse through the Admin Portal without creating an account? Want to see PubNub features instead of just reading about them in the docs?&lt;/p&gt;

&lt;p&gt;We released &lt;a href="https://demo-admin.pubnub.com/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;Public Demo&lt;/a&gt; that gives you insights into sample objects for all PubNub features available in the Admin Portal (apps, keysets, Functions, Business Objects, Users, Dashboards, and many more).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fengd5622tmwx3m6c8p6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fengd5622tmwx3m6c8p6k.png" alt="Public demo" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All PubNub objects are read only and demonstrate a Transport &amp;amp; Logistics use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Membership type (follow-up)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;To follow up on &lt;a href="https://pubnub.com/docs/release-notes/2025/january#membership-type-follow-up" rel="noopener noreferrer"&gt;last month's updates&lt;/a&gt; in the Ruby SDK, we added support for the membership type in the &lt;a href="https://pubnub.com/docs/sdks/python/api-reference/objects#basic-usage-8" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/sdks/php/api-reference/objects#basic-usage-9" rel="noopener noreferrer"&gt;PHP&lt;/a&gt;, and &lt;a href="https://pubnub.com/docs/sdks/dart/api-reference/objects#set-user-metadata" rel="noopener noreferrer"&gt;Dart&lt;/a&gt; SDKs to let you categorize memberships more easily.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Python&lt;/li&gt;
&lt;li&gt;  PHP&lt;/li&gt;
&lt;li&gt;  Dart
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_memberships&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MembershipIncludes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;channel_custom&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some UUID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$includes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PNMembershipIncludes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;$includes&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;channelCustom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;channelType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;channelStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;$addMembership&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setMemberships&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;memberships&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PNChannelMembership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;channel1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BestDish&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pizza&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PNChannelMembership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;channel2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BestDish&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lasagna&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Guest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Away&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$includes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;channelMetadataInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChannelMetadataInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Channel Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BestDish&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pizza&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setChannelMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channelId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;channelMetadataInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;includeStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;includeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Etag support in multiple SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;Several &lt;a href="https://pubnub.com/docs/sdks" rel="noopener noreferrer"&gt;Core SDKs&lt;/a&gt; (C-Sharp, Java, JavaScript, Kotlin, Swift, Unity, Python, and PHP) now support the entity tag in App Context API that you can use to ensure updates only happen if the object hasn't been modified since it was read.&lt;/p&gt;

&lt;p&gt;Use the eTag you received from an applicable get metadata method to check against the server entity tag. If the eTags don't match, an HTTP 412 error is thrown.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handle custom metadata
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We updated App Context API docs for all Core SDKs with a note that the &lt;code&gt;custom&lt;/code&gt; parameter does not support partial updates of user or channel custom metadata.&lt;/p&gt;

&lt;p&gt;Any new custom metadata will completely overwrite existing data on PubNub servers. To handle such updates, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Retrieve the existing metadata using the relevant get object method (like &lt;code&gt;get_channel_metadata()&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; Store the current custom data locally.&lt;/li&gt;
&lt;li&gt; Add any new fields to this stored data.&lt;/li&gt;
&lt;li&gt; Use the relevant set method (like &lt;code&gt;set_channel_metadata()&lt;/code&gt;) to overwrite the existing custom metadata with the updated custom object.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process keeps your existing data intact while adding new information.&lt;/p&gt;

&lt;p&gt;Each SDK now also has an example of how to handle "partial updates" by pulling the current state, altering it, and pushing back to the server (check example for &lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/objects#iteratively-update-existing-metadata" rel="noopener noreferrer"&gt;JavaScript SDK&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Events &amp;amp; Actions ⚡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Secrets in webhook headers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;We now let you use your vault secrets (same as used in Functions) to pass as custom headers in the &lt;strong&gt;Webhook&lt;/strong&gt; action types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhikobl8aqs90ai9nzqu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhikobl8aqs90ai9nzqu3.png" alt="Webhook headers" width="800" height="694"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can assign one or multiple secret keys from your keysets to these custom headers if your webhook requires authorization or you want to enhance your app's security.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtoe5d5gdy3wpxdccnfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtoe5d5gdy3wpxdccnfe.png" alt="Add secrets" width="800" height="949"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  BizOps Workspace 🏢
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Read-only objects
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Following feedback, we improved UI for &lt;strong&gt;User Management&lt;/strong&gt; and &lt;strong&gt;Channel Management&lt;/strong&gt; sections in BizOps Workspace by clearly marking and restricting internal objects, such as users or channels with the &lt;code&gt;PUBNUB_INTERNAL&lt;/code&gt; or &lt;code&gt;REVIEWED&lt;/code&gt; prefixes.&lt;/p&gt;

&lt;p&gt;Such objects are now marked with an "eye" icon and can be viewed only.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bp1oddj1qq6rcz2mb3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bp1oddj1qq6rcz2mb3m.png" alt="Read-only objects" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Illuminate 💡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Increased action history
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Until recently, Illuminate let you see only 50 recent actions that run for Decisions and see why some of them failed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fja0gqyr30432clpjmzj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fja0gqyr30432clpjmzj2.png" alt="Action history button" width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We removed this fixed limit and you can now retrieve the remaining actions from history through the &lt;strong&gt;Load more&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpg0ygi3c1b6j9ims9rhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpg0ygi3c1b6j9ims9rhx.png" alt="Action history" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other 🌟
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A grab bag of changes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Improvement&lt;/p&gt;

&lt;p&gt;Fortunately, we had some time this month to focus on several feedback tickets and improve the existing docs with new examples, clarification, and more.&lt;/p&gt;

&lt;p&gt;Here's the list of changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Documented the missing &lt;code&gt;removeAllPushChannelsForDevice&lt;/code&gt; method in PHP SDK (&lt;a href="https://pubnub.com/docs/sdks/php/api-reference/mobile-push#remove-all-mobile-push-notifications" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Improved info on signals vs messages (&lt;a href="https://pubnub.com/docs/general/messages/publish#messages-vs-signals" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Clarified info across SDKs on when objects events are triggered (&lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/objects" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Clarified send file and publish file methods across SDKs (&lt;a href="https://pubnub.com/docs/sdks/javascript/api-reference/files#send-file" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Showed the use of the &lt;code&gt;sort&lt;/code&gt; field in App Context API for the Swift SDK (&lt;a href="https://pubnub.com/docs/sdks/swift/api-reference/objects#basic-usage-8" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Clarified how the same User ID behaves on multiple devices (&lt;a href="https://pubnub.com/docs/general/setup/users-and-devices#device-level-presence-tracking" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Updated info on presence deltas &amp;amp; interval webhooks (&lt;a href="https://pubnub.com/docs/general/presence/presence-events#presence-deltas" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Added examples of different types of channels (&lt;a href="https://pubnub.com/docs/general/channels/overview#channel-types" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Updated info on the &lt;code&gt;pn_ttl&lt;/code&gt; flag for APNS push notifications (&lt;a href="https://pubnub.com/docs/general/push/ios#additional-parameters" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Documented how to add metadata to push notifications (&lt;a href="https://pubnub.com/docs/general/push/ios#metadata-in-message-payloads" rel="noopener noreferrer"&gt;APNS&lt;/a&gt; &amp;amp; &lt;a href="https://www.pubnub.com/docs/general/push/android?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;FCM&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;  Revisited auth key info in Access Manager (&lt;a href="https://pubnub.com/docs/general/security/access-control" rel="noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
    <item>
      <title>Track Doctor &amp; Patient Presence for Efficient Online Consultations</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Fri, 14 Mar 2025 09:11:24 +0000</pubDate>
      <link>https://dev.to/pubnub/track-doctor-patient-presence-for-efficient-online-consultations-482b</link>
      <guid>https://dev.to/pubnub/track-doctor-patient-presence-for-efficient-online-consultations-482b</guid>
      <description>&lt;p&gt;It is now commonplace for healthcare providers to offer online consultations (also known as telemedicine), which has made accessing healthcare services easier and more convenient for patients whilst making more efficient use of doctors' time. With patient satisfaction at the forefront of the healthcare industry, many providers are looking for ways to improve the patient experience, be transparent about online doctor availability, and allow potential patients to make informed decisions.&lt;/p&gt;

&lt;p&gt;Being able to track doctors' and patients' online presence in real time can improve everyone's overall experience. This blog will explore how to track users and discuss exactly how this can improve your workflow.&lt;/p&gt;

&lt;p&gt;Consider the idealized, ‘standard’ experience for an online, appointment-based consultation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The patient schedules the appointment at a specific date and time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The doctor's calendar is updated with the scheduled appointment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Both the patient and the doctor join the virtual consultation room at the same time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The consultation ends exactly on time, with all the patient’s issues resolved.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Clearly, this never happens!&lt;/strong&gt; The patient might join late, or miss their appointment, wasting the doctor’s time. Equally, the doctor might be running late with their previous appointment, leaving the patient waiting. There is no way for either party to know that the other is late, or absent, leading to frustration and inefficiencies.&lt;/p&gt;

&lt;p&gt;Imagine if you knew when a patient joined a chat, how many patients were waiting to chat with a specific doctor, or whether or not the doctor was in an existing consultation. Then you could keep the patient up to date with how many people are queued in front of them, or send them an automated message that ‘the doctor is running a few minutes late’.&lt;/p&gt;

&lt;p&gt;You can also start to build more complex use cases, where multiple specialist doctors can flexibly provide on-demand consultations to multiple patients and track the patient journey from triage to consultation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Track Whether a Patient or Doctor is Available?
&lt;/h2&gt;

&lt;p&gt;PubNub will represent both doctors and patients as &lt;a href="https://www.pubnub.com/docs/general/setup/users-and-devices?" rel="noopener noreferrer"&gt;users&lt;/a&gt; and the &lt;a href="https://www.pubnub.com/docs/general/presence/overview?" rel="noopener noreferrer"&gt;Presence feature&lt;/a&gt; lets you track whether or not a user is currently subscribed to a &lt;a href="https://www.pubnub.com/docs/general/channels/overview?" rel="noopener noreferrer"&gt;channel&lt;/a&gt;. Think of a channel as a shared space that users can join, so you might have a channel to represent the ‘lobby’ where patients are waiting to see a doctor and a separate channel to represent the 1:1 ‘consultation’ with that doctor. When a user joins or leaves a channel, a notification is sent to all registered clients, so you always know who else is present and listening on the channel (there are, of course, ways to restrict who can see your presence, or who can access specific channels, which I’ll touch on later).&lt;/p&gt;

&lt;p&gt;A user’s presence can also have state information associated with it, allowing you to provide some context. For example, just because a user is present does not mean they are ‘available’ as they might be ‘busy’ or ‘do not disturb’ - so you can capture the user’s &lt;em&gt;actual&lt;/em&gt; availability using a combination of &lt;a href="https://www.pubnub.com/docs/general/presence/overview?" rel="noopener noreferrer"&gt;Presence&lt;/a&gt; and &lt;a href="https://www.pubnub.com/docs/general/presence/presence-state?" rel="noopener noreferrer"&gt;Presence State&lt;/a&gt;. Note that Presence state cannot be used for data that needs to persist after the appointment, so use &lt;a href="https://www.pubnub.com/docs/general/metadata/basics?" rel="noopener noreferrer"&gt;App Context&lt;/a&gt; for non-transitory data, or &lt;a href="https://www.pubnub.com/blog/do-i-have-to-store-my-data-with-pubnub/?" rel="noopener noreferrer"&gt;store it outside of PubNub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is a lot easier to understand with a demo!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The embedded application below will show you how many users are currently viewing this page. If you open the demo in a new tab (or open this blog in a new tab), you will see the number of online users increase, and closing tabs will have the opposite effect. You can also set your presence state - hardcoded in the demo as &lt;code&gt;available&lt;/code&gt; or &lt;code&gt;busy&lt;/code&gt;, but PubNub does not restrict what value the user’s ‘state’ can be. Have a play with the demo - notice that the values will update in real-time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pubnubdevelopers.github.io/mini-samples/presence-state/" rel="noopener noreferrer"&gt;Viewing on a mobile device? Click here to see the demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This page contains embedded content that is not supported by this site&lt;/strong&gt; , please view it at &lt;a href="https://pubnubdevelopers.github.io/mini-samples/presence-state/" rel="noopener noreferrer"&gt;https://pubnubdevelopers.github.io/mini-samples/presence-state/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How Does the Demo Work?
&lt;/h3&gt;

&lt;p&gt;The application uses the &lt;a href="https://www.pubnub.com/docs/sdks/javascript?" rel="noopener noreferrer"&gt;PubNub Core JavaScript SDK&lt;/a&gt;, and the full source code of the demo is available on &lt;a href="https://github.com/PubNubDevelopers/presence-mini-sample" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ignoring the connective tissue of the app, the key portions that relate to PubNub Presence are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//  Subscribe to a channel and receive presence events&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lobbyChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CHANNEL_NAME&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lobbySubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lobbyChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;receivePresenceEvents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//  Callback which will be invoked when a presence event happens&lt;/span&gt;
&lt;span class="nx"&gt;lobbySubscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onPresence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;join&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state-change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;//  Called whenever a user joins a channel or their state changes&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leave&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;//  Called whenever a user leaves a channel&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;interval&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;//  This allows you to track the presence for very large channels, but you are unlikely to need this for healthcare use cases&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;//  Subscribe to the channel to receive presence events and notify others we have joined&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;lobbySubscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you set yourself as &lt;code&gt;available&lt;/code&gt; or &lt;code&gt;busy&lt;/code&gt;, the &lt;code&gt;setState&lt;/code&gt; API is used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CHANNEL_NAME&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;onlineStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the application first loads, it will also use the &lt;a href="https://www.pubnub.com/docs/sdks/javascript/api-reference/presence#here-now?" rel="noopener noreferrer"&gt;hereNow&lt;/a&gt; API to determine which users are already connected to the channel.&lt;/p&gt;

&lt;p&gt;If you would like to understand PubNub's Presence feature in more detail, &lt;a href="https://www.pubnub.com/docs/general/presence/overview?" rel="noopener noreferrer"&gt;our docs&lt;/a&gt; are a great place to start. To avoid straying off-topic, the rest of this blog will look at how you can use PubNub Presence to enhance online healthcare consultations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo Data Security
&lt;/h3&gt;

&lt;p&gt;The demo is designed to show the high-level principles of PubNub Presence, and is not designed to show security best practices. Especially with patient healthcare data, you would likely implement much of the business logic on your server, and ensure users only have visibility to the data they need using &lt;a href="https://www.pubnub.com/blog/how-to-build-a-real-time-patient-monitoring-system/?" rel="noopener noreferrer"&gt;access control&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Patient Consultations
&lt;/h2&gt;

&lt;p&gt;Let’s consider two architectures for virtual consultations:&lt;/p&gt;

&lt;p&gt;The first is an appointment-based system where prospective patients will set up scheduled appointments with doctors ahead of time, and meet with the doctor for a set period of time.&lt;/p&gt;

&lt;p&gt;The second allows for on-demand, or instant, consultations, where patients needing treatment can join a virtual queue, get assessed and prioritized, and then move on to specialist treatment with a doctor who is assigned based on their skillset and availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appointment-Based Remote Consultations
&lt;/h3&gt;

&lt;p&gt;The most common type of virtual appointment is scheduled in advance and involves the patient and doctor joining a virtual ‘meeting room’ at the specified time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F12bbfd9e03d040a2ba30dcf0651e6670" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F12bbfd9e03d040a2ba30dcf0651e6670" alt="Appointment-Based Remote Consultations" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When scheduling the appointment, the patient will have pre-registered with the healthcare provider and provided some details about their condition before selecting an appointment time. This is not included in the above diagram.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; At the pre-appointed time, the patient will join a lobby specific to that doctor. So, if there are two doctors, there will be two lobbies, &lt;code&gt;lobby.doctor1&lt;/code&gt; and &lt;code&gt;lobby.doctor2&lt;/code&gt;. A &lt;code&gt;join&lt;/code&gt; event is generated when the patient arrives, allowing the doctor to see how many patients are waiting at any time.&lt;/p&gt;

&lt;p&gt;The doctor can maintain their &lt;code&gt;presence state&lt;/code&gt; either manually or automatically, allowing patients to see whether their doctor is currently ‘busy’, ‘unavailable’, or that the consultation will start soon.&lt;/p&gt;

&lt;p&gt;Data security is paramount, and channels should be restricted using PubNub’s &lt;a href="https://www.pubnub.com/docs/general/basics/manage-access?" rel="noopener noreferrer"&gt;Access Manager&lt;/a&gt;, to ensure data is only available to those who need it. For example, the &lt;code&gt;lobby.doctor1&lt;/code&gt; should not be visible to any doctor other than &lt;code&gt;doctor1&lt;/code&gt;. How to achieve this will be shown later in this blog.&lt;/p&gt;

&lt;p&gt;PubNub allows you to &lt;a href="https://www.pubnub.com/docs/general/basics/send-messages?" rel="noopener noreferrer"&gt;send secure messages&lt;/a&gt; between the doctor and patient, so even before the consultation begins, messages could be exchanged on the &lt;code&gt;lobby.&amp;lt;doctor&amp;gt;.&amp;lt;patientId&amp;gt;&lt;/code&gt; channel, which is specific and private for each patient. You might even have a workflow, triggered by a patient &lt;code&gt;joining&lt;/code&gt; a lobby, where some heuristic process determines that the doctor is running late and can send automated messages to the patient keeping them updated on expected wait times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; When the doctor starts the consultation, the patient leaves the &lt;code&gt;lobby.&amp;lt;doctor&amp;gt;&lt;/code&gt; channel and joins the &lt;code&gt;consultation.&amp;lt;doctor&amp;gt;.&amp;lt;patient&amp;gt;&lt;/code&gt; channel. Leaving &lt;code&gt;lobby.&amp;lt;doctor&amp;gt;&lt;/code&gt; will generate a &lt;code&gt;leave&lt;/code&gt; event and automatically update all interested parties that the queue length has reduced; the doctor will also set their &lt;code&gt;presence state&lt;/code&gt; to indicate they are in a consultation which will notify anyone who has registered for updates.&lt;/p&gt;

&lt;p&gt;The consultation channel, &lt;code&gt;consultation.&amp;lt;doctor&amp;gt;.&amp;lt;patient&amp;gt;&lt;/code&gt;, is unique and private to that doctor &amp;amp; patient; data exchanged over this channel can be backed up or retained as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  On-Demand (Instant) Remote Consultations
&lt;/h3&gt;

&lt;p&gt;Although not as common as scheduled appointments, some healthcare organizations offer on-demand virtual consultations, where a patient can log in and wait to see an available doctor or specialist.&lt;/p&gt;

&lt;p&gt;The following diagram captures the workflow of a patient requesting an on-demand consultation. It presupposes that the patient has registered with the provider and provided details about their symptoms. Data that needs to be persistent, such as medical information and a record of the consultation itself, is not shown on this diagram, which focuses on the transitory data associated with the patients’ and doctors’ presence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F03fe37880f324093a692c82973a88750" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F03fe37880f324093a692c82973a88750" alt="On-Demand Remote Consultations" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Since there is no single workflow for on-demand virtual healthcare, I have shown a representative case study&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; A patent enters the workflow after requesting a virtual consultation. The patient is first placed into an initial triage queue, &lt;code&gt;lobby.triage&lt;/code&gt;, where they provide additional information about their symptoms. This triage might be automated, or handled by a human, but the outcome will be a categorization of the patient along with some assessment of the urgency of their case.&lt;/p&gt;

&lt;p&gt;Joining &lt;code&gt;lobby.triage&lt;/code&gt; will generate a &lt;code&gt;join&lt;/code&gt; event, giving you real-time visibility into how many people are currently being triaged, and eventually determining the time between a patient entering triage and that same patient entering a consultation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; After triage, the patient is assigned to a specialist queue, which generates a &lt;code&gt;leave&lt;/code&gt; event for the &lt;code&gt;lobby.triage&lt;/code&gt; channel and a &lt;code&gt;join&lt;/code&gt; event for the &lt;code&gt;lobby.&amp;lt;specialist&amp;gt;&lt;/code&gt; channel. At this point, interested parties can see how many patients are waiting to be seen by a doctor, and how much demand there is for each specialist in real-time. Patients can be updated on how many people are in front of them in their queue, and doctors can use this information to prioritize who they will speak with next, for example, patients in the ‘urgent’ queue will take priority over those in the ‘general’ queue.&lt;/p&gt;

&lt;p&gt;After triage, the queue categorizations will vary from healthcare provider to healthcare provider, and can even vary based on which doctors are available and their skillsets. I have chosen to categorize &lt;code&gt;pediatric&lt;/code&gt;, &lt;code&gt;general&lt;/code&gt;, and &lt;code&gt;urgent&lt;/code&gt; in the above diagram as this is most typical, but you could also break &lt;code&gt;general&lt;/code&gt; down further into &lt;code&gt;cardiology&lt;/code&gt;, &lt;code&gt;orthopedics&lt;/code&gt;, etc., for example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; The patient will join the consultation with the doctor, generating a &lt;code&gt;leave&lt;/code&gt; event for the channel they were waiting in and allowing the system to calculate the time between triage and seeing a doctor. The doctors also generate a &lt;code&gt;join&lt;/code&gt; event as they start the consultation, giving a real-time overview of how many doctors are in active consultations and how many are waiting to see patients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping Patient Data Secure
&lt;/h2&gt;

&lt;p&gt;It is critically important to keep all healthcare patient data secure, not just for legal and regulatory compliance but also to protect the privacy of patients and healthcare professionals. Electronic Health Records (EHR) can be highly sensitive and personal, including medical histories, diagnoses, treatments, and more.&lt;/p&gt;

&lt;p&gt;PubNub enables you to easily build &lt;a href="https://www.pubnub.com/blog/hipaa-compliant-chat/?" rel="noopener noreferrer"&gt;HIPAA compliant&lt;/a&gt; real-time solutions, but what does HIPAA compliance mean? HIPAA stands for the &lt;a href="https://www.pubnub.com/blog/what-is-hipaa-understanding-business-compliance-requirements/?" rel="noopener noreferrer"&gt;Health Insurance Portability&lt;/a&gt; and Accountability Act, which aims to protect patients’ protected health information (PHI). If any of the &lt;a href="https://www.pubnub.com/blog/hipaa-identifiers/?" rel="noopener noreferrer"&gt;18 protected identifiers&lt;/a&gt; appear in a message, that message is considered to contain PHI and can only be exchanged with &lt;a href="https://www.pubnub.com/docs/setup/data-security#message-encryption?" rel="noopener noreferrer"&gt;end-to-end encryption&lt;/a&gt;, using a solution that supports access controls and auditing.&lt;/p&gt;

&lt;p&gt;What about outside of the USA? At PubNub, we often discuss HIPAA Compliance because it resonates strongly with our customer base and is understood by customers worldwide. Globally, PubNub is compliant with a &lt;a href="https://www.pubnub.com/trust/compliance/?" rel="noopener noreferrer"&gt;number of industry regulations&lt;/a&gt; such as ISO 27001, SOC2, and &lt;a href="https://www.pubnub.com/trust/legal/gdpr/?" rel="noopener noreferrer"&gt;GDPR&lt;/a&gt;, so you can have confidence developing a healthcare solution with PubNub regardless of your worldwide footprint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access Control Example
&lt;/h3&gt;

&lt;p&gt;Recall previously, when speaking about Appointment-Based Remote Consultations, I said the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Data security is paramount, and channels should be restricted using PubNub’s &lt;a href="https://www.pubnub.com/docs/general/basics/manage-access?" rel="noopener noreferrer"&gt;Access Manager&lt;/a&gt;, to ensure data is only available to those who need it. For example, the &lt;code&gt;lobby.doctor1&lt;/code&gt; should not be visible to any doctor other than &lt;code&gt;doctor1&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You would implement this as follows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite:&lt;/strong&gt; Access Manager is &lt;a href="https://www.pubnub.com/docs/general/security/access-control#configuration?" rel="noopener noreferrer"&gt;enabled on your PubNub keyset&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; When the doctor application initializes, the doctor logs in and authenticates themself using your existing auth flow. As part of authentication, your application should also make a &lt;code&gt;grant&lt;/code&gt; request to PubNub. This is steps 1 and 2 in the oft-reused diagram taken from our &lt;a href="https://www.pubnub.com/docs/general/security/access-control#authorization-flow?" rel="noopener noreferrer"&gt;documentation on auth flow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhxjb9ro9l28t2egf3iz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhxjb9ro9l28t2egf3iz.png" alt="PubNub Access Manager Authorization Flow" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The grant request on your server would look something like this in Node (though we do support other languages). See the &lt;a href="https://www.pubnub.com/docs/sdks/javascript/api-reference/access-manager#methods?" rel="noopener noreferrer"&gt;grantToken documentation&lt;/a&gt; for more detail on what each field means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="c1"&gt;//  The doctor’s ID who is requesting access&lt;/span&gt;
  &lt;span class="na"&gt;authorized_uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;doctor1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;//  Able to set and read presence information for this (and only this) &lt;/span&gt;
&lt;span class="c1"&gt;//  doctor’s lobby&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lobby.doctor1-pnpres&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="c1"&gt;//  Able to exchange private lobby messages between doctor1 and &lt;/span&gt;
&lt;span class="c1"&gt;//  patient1, and nobody else.  Shown as optional on the diagram.&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lobby.doctor1.patient1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="c1"&gt;//  Able to exchange private consultation messages between &lt;/span&gt;
&lt;span class="c1"&gt;//  doctor1 and patient1 &lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;consultation.doctor1.patient1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//  todo send this back to the client&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; The token returned in the previous call should be returned to the client, who should, in turn, call &lt;a href="https://www.pubnub.com/docs/sdks/javascript/api-reference/access-manager#set-token?" rel="noopener noreferrer"&gt;setToken&lt;/a&gt; on their client SDK. This is covered by steps 3, 4, and 5 in the above diagram. Again, although the links and examples are given in JavaScript, PubNub has SDKs to support all popular client languages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Whenever the existing rule’s TTL expires, or new access rules are needed, repeat steps 1 and 2. For example, if a new patient joins the waiting room, you might want to set a new rule to allow the doctor to chat with this new patient&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking Patient Metrics
&lt;/h2&gt;

&lt;p&gt;This blog has focused heavily on taking action in real time to improve the patient experience and keep all parties updated as patients move through the system.&lt;/p&gt;

&lt;p&gt;I will not go into detail about the following use cases, but if you are tracking user presence anyway, be aware that it would be trivial to implement some additional features:&lt;/p&gt;

&lt;h3&gt;
  
  
  Admin Dashboards:
&lt;/h3&gt;

&lt;p&gt;An administrator user who has access to all channel presence events could be given an overview of the current solution state, including how many patients are waiting for each doctor, how each doctor is performing, and historical trends. This could allow the administrator to make resourcing decisions (if a doctor suddenly becomes unavailable) or perhaps move patients between doctors if queues get too long, improving patient care and the overall patient experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analytics:
&lt;/h3&gt;

&lt;p&gt;PubNub Events &amp;amp; Actions (E&amp;amp;A) allows you to send the real-time data generated by your system to third parties for storage or analytics. For example, you can send data to Amazon SQS, Amazon Kinesis, Amazon S3, or Apache Kafka.&lt;/p&gt;

&lt;p&gt;E&amp;amp;A can ingest Presence events, meaning you can easily set up a rule to export all &lt;code&gt;join&lt;/code&gt;, &lt;code&gt;leave&lt;/code&gt;, and &lt;code&gt;state-change&lt;/code&gt; events for later analysis or storage in a third-party system. This provides historical analytics and trend data without having to write any code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;If you haven’t already, check out our &lt;a href="https://www.pubnub.com/solutions/digital-health/?" rel="noopener noreferrer"&gt;digital health landing page&lt;/a&gt;, which discusses implementing a healthcare solution with PubNub more generally and highlights some customer testimonials.&lt;/p&gt;

&lt;p&gt;If you would like to take the first step towards adding to those customer testimonials or just learn more, you can &lt;a href="https://www.pubnub.com/company/contact-sales/?" rel="noopener noreferrer"&gt;get in touch with us&lt;/a&gt; or &lt;a href="https://admin.pubnub.com/#/register?" rel="noopener noreferrer"&gt;start development with a free account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally... although patient health remains the primary focus for medical practices as they transition from face-to-face, in-person care to telehealth consultations, no primary care provider can ignore the impact of social media and online reputation for their organization. Especially where medical services are subject to competition or services are provided to a younger demographic, you must also consider online patient engagement, including search engine ranking, SEO, and your presence on social media platforms. Optimizing your appointment scheduling will lead to an improved patient relationship and better patient reviews and provide you with a positive and strong online presence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.builder.io%2Fapi%2Fv1%2Fpixel%3FapiKey%3D0ee4d50ccdc943eda308d1099e2b1915" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.builder.io%2Fapi%2Fv1%2Fpixel%3FapiKey%3D0ee4d50ccdc943eda308d1099e2b1915" width="1" height="1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How can PubNub help you?
&lt;/h1&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://www.pubnub.com/blog/track-doctor-patient-presence-for-efficient-online-consultations/?" rel="noopener noreferrer"&gt;PubNub.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our platform helps developers build, deliver, and manage real-time interactivity for web apps, mobile apps, and IoT devices.&lt;/p&gt;

&lt;p&gt;PubNub is the world's largest event-driven network, offering less than 30ms latency with global delivery, unlimited concurrency, and 99.999% reliability&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience PubNub
&lt;/h2&gt;

&lt;p&gt;Check out &lt;a href="https://www.pubnub.com/tour/introduction/?" rel="noopener noreferrer"&gt;Live Tour&lt;/a&gt; to understand the essential concepts behind every PubNub-powered app in less than 5 minutes&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Setup
&lt;/h2&gt;

&lt;p&gt;Sign up for a &lt;a href="https://admin.pubnub.com/?" rel="noopener noreferrer"&gt;PubNub account&lt;/a&gt; for immediate access to PubNub keys for free&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.pubnub.com/docs?" rel="noopener noreferrer"&gt;PubNub docs&lt;/a&gt; will get you up and running, regardless of your use case or &lt;a href="https://www.pubnub.com/docs?" rel="noopener noreferrer"&gt;SDK&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Gamifying Your Application With Real-time Interactivity</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Tue, 25 Feb 2025 15:00:44 +0000</pubDate>
      <link>https://dev.to/pubnub/gamifying-your-application-with-real-time-interactivity-43pl</link>
      <guid>https://dev.to/pubnub/gamifying-your-application-with-real-time-interactivity-43pl</guid>
      <description>&lt;p&gt;Gamification is more than just a buzzword—it’s a proven strategy that works. Whether you're building a mobile app or website, everyone and their grandma uses this gamification magic, and your competitors are in on the secret, too. So, what does gamification do, and how do I apply it to your application?&lt;/p&gt;

&lt;p&gt;First, gamification can be applied anywhere, even in the real world. Whether hosting an event live, a sports streaming feature, or creating an interactive app, live engagement tools like fan chat, live reaction, trivia, and loyalty points will incentivize users to return for an engaging experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Why Does Gamification Work?
&lt;/h2&gt;

&lt;p&gt;According to the Oxford Online Dictionary:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Gamification is the practice of making activities more like games to make them more interesting or enjoyable.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In other terms, gamification uses the concepts of video games and applies them to non-game contexts to render experiences more engaging and rewarding to create more interactive content.&lt;/p&gt;

&lt;p&gt;Gamification techniques are everywhere, even in the physical world, to increase user interactions and retention. Examples of gamified apps: If you're a Starbucks customer and you earn "stars" toward a free meal or drink, you're playing a game designed to get you to purchase more. Another great example is Duolingo, where points, streaks, and badges are awarded for daily language learning—turning the learning experience or learning process into an addictive one by making you feel a sense of accomplishment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of Real-time Interactivity
&lt;/h2&gt;

&lt;p&gt;Developing these real-time experiences isn't merely a matter of including a real-time leaderboard or some kind of interactive quest in your application—it's about real-time engagement that forms user incentives and brings them back to your app.&lt;/p&gt;

&lt;p&gt;These gamified features only work if they are done in real-time. Slowed-down interactions destroy momentum, increasing the churn rate and ruining your user experience. Worry not—PubNub is here for your app development!&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Real-time Gamified Experience
&lt;/h2&gt;

&lt;p&gt;Now that you understand the importance of adding gamified elements to your app, let’s explore how to build these features. Whether you want to implement live chat, reactions, polls, or a rewards program, you will need a system that can effectively handle real-time updates.&lt;/p&gt;

&lt;p&gt;So, let’s add gamification elements to our app using our &lt;a href="https://www.pubnub.com/docs/sdks?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;PubNub SDKs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up The Communication Layer
&lt;/h3&gt;

&lt;p&gt;We will need a real-time messaging layer to handle instant updates. This ensures that all interactions, such as poll votes, chat messages, or reward notifications, reach all users immediately.&lt;/p&gt;

&lt;p&gt;This is the most critical stage—it provides the foundation for a smooth and immersive gamified experience. With no real-time updates, the interactions are no longer exciting, and people lose interest.&lt;/p&gt;

&lt;h4&gt;
  
  
  JavaScript (Web)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Install Dependencies&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize the Messaging Client&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PubNub&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pubnub&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;publishKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-publish-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subscribeKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-subscribe-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-unique-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Kotlin (Android)
&lt;/h4&gt;

&lt;p&gt;If you are creating an application in Kotlin, choose which dependency installation makes sense for your project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Gradle (Android Studio Projects)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;implementation&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;com.pubnub:pubnub-kotlin:10.4.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize the Messaging Client&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PNConfiguration&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PubNub&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserId&lt;/span&gt;
&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PNConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myUserId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;publishKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-publish-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;subscribeKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-subscribe-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Swift (IOS)
&lt;/h4&gt;

&lt;p&gt;If you are creating an application in Swift, choose which dependency installation makes sense for your project.&lt;/p&gt;

&lt;p&gt;Use Swift Package Manager In your Package.swift file, add the following dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PNConfiguration&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PubNub&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserId&lt;/span&gt;
&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PNConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myUserId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;publishKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-publish-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;subscribeKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-subscribe-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use CocoaPods&lt;/strong&gt; Ensure you have the latest CocoaPods installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;gem&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;cocoapods&lt;/span&gt;
&lt;span class="nx"&gt;gem&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="nx"&gt;cocoapods&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add PubNub to your Podfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pod&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PubNubSwift&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~&amp;gt; 8.3.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Carthage&lt;/strong&gt; Add the following to your Cartfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;github&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pubnub/swift&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;~&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;8.3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize Messaging Client (Swift)&lt;/strong&gt; Import &amp;amp; configure PubNub in AppDelegate (Check implementation below for multiple scenes, IOS 13+)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UIKit&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PubNub&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UIApplicationMain&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIResponder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UIApplicationDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PubNub&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIWindow&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

  &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;willFinishLaunchingWithOptions&lt;/span&gt; &lt;span class="nx"&gt;launchOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LaunchOptionsKey&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nil&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PubNubConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;publishKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-publish-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;subscribeKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-subscribe-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;pubnub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize Messaging Client For Multiple Scenes (IOS 13+)&lt;/strong&gt; Modify SceneDelegate.swift to pass PubNub to the view controllers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UIKit&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PubNub&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iOS&lt;/span&gt; &lt;span class="mf"&gt;13.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SceneDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIResponder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UIWindowSceneDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIWindow&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIScene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;willConnectTo&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UISceneSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="nx"&gt;connectionOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIScene&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConnectionOptions&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PubNubConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;publishKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-publish-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;subscribeKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-subscribe-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;pubnub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bringing Gamification to Life
&lt;/h2&gt;

&lt;p&gt;Where gamification is involved, you have a lot of freedom, and with PubNub, we get to let these ideas run wild. The game elements you choose to include in your application don’t necessarily have to feel like games. For instance, gamification can be as simple as an onboarding procedure that walks you through a progress indicator and a reward, such as access to more features in your application.&lt;/p&gt;

&lt;p&gt;In this blog, we will walk you through one example of gamification: creating a live leaderboard that lets users track their high scores. The use case will be in a live event application where users answer trivia questions about their favourite sports team. The leaderboard will rank who got the most questions right, and users will receive live updates about their independent scores and rewards for participating in the trivia.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it will work:&lt;/strong&gt; Users will earn points by answering questions during a game or live event. Scores update instantly, ensuring everyone sees changes as they happen The leaderboard dynamically ranks players, motivating them to stay engaged&lt;/p&gt;

&lt;p&gt;Let’s break it down step-by-step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Broadcasting Score Updates in Real Time
&lt;/h3&gt;

&lt;p&gt;The first thing in creating a live leaderboard is to ensure that every time a player gains points, his or her score gets updated and streamed in real-time to other users on your application.&lt;/p&gt;

&lt;p&gt;We achieve this by publishing messages to the “leaderboard” channel, which we will subscribe to using a PubNub Function later in the blog.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works:&lt;/strong&gt; Each time a user earns points, we publish an updated score request The message published will contain the user’s ID and their new score&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateScore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newScore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newScore&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;storeInHistory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Score published:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error publishing score:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// Example: A player earns 50 points&lt;/span&gt;
&lt;span class="nf"&gt;updateScore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;player123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every score update is broadcast to every User / PubNub Function who is subscribed to the “leaderboard” channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Subscribing to Leaderboard Updates
&lt;/h3&gt;

&lt;p&gt;To ensure real-time rankings, all users should dynamically listen for new scores, and the UI should reflect that. To do this, we’ll create a &lt;a href="https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;subscriptionset&lt;/a&gt; that will allow us to handle multiple event types that PubNub supports efficiently.&lt;/p&gt;

&lt;p&gt;Below, I will include all the different event types that PubNub supports. For this demo, we will utilize the &lt;strong&gt;OnMessage&lt;/strong&gt; to deliver the leaderboard ranks as a “Message.” For another example of gamification, you might use PubNub Signals (for smaller messages), utilizing the &lt;strong&gt;OnSignal&lt;/strong&gt; event listener for live reactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript (Web)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Let&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscriptionSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaderboard_scores&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;leaderboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error processing leaderboard update:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;updateLeaderboard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out other listeners that might be helpful for your application below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onPresence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Presence event: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signalEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Signal event: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signalEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onObjects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objectsEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Objects event: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;objectsEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessageAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messageActionEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message Reaction event: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messageActionEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;subscriptionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;File event: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Storing Scores with PubNub Functions
&lt;/h4&gt;

&lt;p&gt;A leaderboard in real-time is wonderful, but what happens when users reload or close the application? We need a way of persisting scores. Instead of using App Context, we can cache scores using PubNub Functions via KV Store to dynamically update player scores.&lt;/p&gt;

&lt;p&gt;We will use PubNub Functions with the KV Store to keep the leaderboard data persistent. This will allow us to dynamically store, retrieve and update a user's score without relying on an external database.&lt;/p&gt;

&lt;p&gt;Create a PubNub Function&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to the &lt;a href="https://admin.pubnub.com/#/login?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;PubNub Admin Portal&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to Functions → Select “Create Package”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Name the Function and select the event type “Before Publish on Fire”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Name the channel you would want the function to watch for events (messages) on. In this case, we will use the channel “leaderboard”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy and paste the code shown below in the Functions editor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click “Deploy” Function and specify the keyset you would like to deploy your function under&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add KV Store for Persistent Storage&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use db.get(“leaderboard”) to retrieve stored scores&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use db.set(“leaderboard”, updated data) to persist new scores&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F58ef09afc4b746508818ebfab97c873b" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F58ef09afc4b746508818ebfab97c873b" alt="PubNub Functions Gamification" width="800" height="398"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;kvstore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pubnub&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Fetch existing leaderboard or initialize an empty one&lt;/span&gt;
    &lt;span class="c1"&gt;// db.removeItem("leaderboard");&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Ensure leaderboard structure is correct&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;leaderboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// If username is null or undefined, just publish the existing leaderboard&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaderboard_scores&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Insert new score in sorted order&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;newScore&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Trim leaderboard to top 10 entries&lt;/span&gt;
    &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaderboard_scores&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Displayer the Live Leaderboard
&lt;/h4&gt;

&lt;p&gt;Now that we’ve successfully set up real-time score broadcasting, subscription handling, and persistent storage with PubNub Functions, the final step is to fetch the initial leaderboard.&lt;/p&gt;

&lt;p&gt;To achieve this, we can publish a message to the PubNub Function, which will publish a message back on “leaderboard_scores”. Above, we have created a “subscriptionset” subscribing to channel “leaderboard_scores” to receive the leaderboard data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchInitialLeaderboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error fetching initial leaderboard:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enhancing Gamification with AppContext
&lt;/h2&gt;

&lt;p&gt;We have built a real-time leaderboard with PubNub Functions utilizing the KV store for persistent storage. What if we wanted to take gamification even further? This is where &lt;a href="https://www.pubnub.com/how-to/use-app-context/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;AppContext&lt;/a&gt; come into play.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using AppContext for Persistent Player Storage
&lt;/h3&gt;

&lt;p&gt;While the KV Store is ideal for storing and updating data like leaderboard ranks, &lt;a href="https://www.pubnub.com/docs/general/metadata/basics?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;App Context&lt;/a&gt; is designed to store player metadata across sessions.&lt;/p&gt;

&lt;p&gt;For example, instead of only showing the highest leaderboard scores, you could personalize your application to display a player’s all-time ranking, achievements, and progress toward the next reward level. Personalization through player profiles creates a good customer experience as users are motivated and engaged even if they are not ranked on the leaderboard. In other words, think of AppContext as storing and retrieving player profiles instead of the highest scores of all players, as that is what we used the KV store for.&lt;/p&gt;

&lt;p&gt;So what does this look like?&lt;/p&gt;

&lt;p&gt;First, we need to enable App Context on our keyset like such:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F706a1183934445d1b6bcaed70806ac48" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F706a1183934445d1b6bcaed70806ac48" alt="Enable App Context" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now make a new function to save your score to a profile that can be retrieved later, utilizing App Context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Function to upload user's score to App Context&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadUserScore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setUUIDMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Set the user's UUID as their name&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Successfully updated steps for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error uploading user score to App Context:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To retrieve the initial score, we can use the function “getUUIDMetadata ” specifying a uuid for the user for which we want to retrieve a score for. When we navigate to &lt;a href="https://www.pubnub.com/products/bizops-workspace/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;BizOps Workspace&lt;/a&gt;, the management console for AppContext, we should now see the score or, in this case, steps uploaded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Fad9d87f7162a495c93a4a68eea03babc" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Fad9d87f7162a495c93a4a68eea03babc" alt="View BizOps Workspace" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Repurposing PubNub Demos for Gamification
&lt;/h2&gt;

&lt;p&gt;PubNub offers many demos that are very quickly supported in the context of gamifying your sports media &amp;amp; entertainment app. Whether you are working on fan engagement, financial awards, or interactive leaderboards, these demos provide a solution to integrate real-time gamification features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Case for Gamification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pubnub.com/demos/live-events/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;Live Events Chat&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fan chat for sports, concerts, or esports events, complete with live reactions and polls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pubnub.com/demos/push/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;Push Notifications&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instant updates on leaderboard changes, reward system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pubnub.com/demos/chat-sdk-mobile/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;Chat SDK Mobile&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In-game chat with team-based interactions, challenges, and real-time engagement to boost social interaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pubnub.com/demos/fintech/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;FinTech Chat&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gamify financial apps with loyalty rewards, spending challenges, and cashback leaderboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Gamify Your App?
&lt;/h2&gt;

&lt;p&gt;Gamification isn’t just a trend—it’s a powerful tool that works. By incorporating game design, game mechanics, and game-like elements, you can create interactive experiences that captivate user engagement, creating user motivation for them to keep coming back. Whether you are building a live event, sports, or interactive website, leveraging real-time interactivity ensures users stay engaged, charged, and immersed in the experience. Combining active rewards, challenges, and competition turns passive interaction into an interactive experience that builds a stronger connection between your application and your users.&lt;/p&gt;

&lt;p&gt;By leveraging PubNub’s real-time capabilities, whether with our SDKs, PubNub Functions, and AppContext, you can add features such as live leaderboards, rewards, real-time chat, or interactive challenges without worrying about infrastructure or scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Started Today
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://admin.pubnub.com/#/login?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;Sign up for a free account&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pubnub.com/docs/sdks?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;PubNub SDK documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pubnub.com/docs/serverless/functions/overview?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;Functions Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pubnub.com/docs/general/metadata/basics?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;App Context Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.builder.io%2Fapi%2Fv1%2Fpixel%3FapiKey%3D0ee4d50ccdc943eda308d1099e2b1915" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.builder.io%2Fapi%2Fv1%2Fpixel%3FapiKey%3D0ee4d50ccdc943eda308d1099e2b1915" width="1" height="1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How can PubNub help you?
&lt;/h1&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://www.pubnub.com/blog/gamifying-your-application-with-real-time-interactivity/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;PubNub.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our platform helps developers build, deliver, and manage real-time interactivity for web apps, mobile apps, and IoT devices.&lt;/p&gt;

&lt;p&gt;The foundation of our platform is the industry's largest and most scalable real-time edge messaging network. With over 15 points-of-presence worldwide supporting 800 million monthly active users, and 99.999% reliability, you'll never have to worry about outages, concurrency limits, or any latency issues caused by traffic spikes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience PubNub
&lt;/h2&gt;

&lt;p&gt;Check out &lt;a href="https://www.pubnub.com/tour/introduction/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;Live Tour&lt;/a&gt; to understand the essential concepts behind every PubNub-powered app in less than 5 minutes&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Setup
&lt;/h2&gt;

&lt;p&gt;Sign up for a &lt;a href="https://admin.pubnub.com/signup/?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;PubNub account&lt;/a&gt; for immediate access to PubNub keys for free&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.pubnub.com/docs?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;PubNub docs&lt;/a&gt; will get you up and running, regardless of your use case or &lt;a href="https://www.pubnub.com/docs?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=off_domain&amp;amp;utm_content=en" rel="noopener noreferrer"&gt;SDK&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deliver Personalized Content to Your Stream Audience</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Mon, 17 Feb 2025 09:19:23 +0000</pubDate>
      <link>https://dev.to/pubnub/deliver-personalized-content-to-your-stream-audience-26g0</link>
      <guid>https://dev.to/pubnub/deliver-personalized-content-to-your-stream-audience-26g0</guid>
      <description>&lt;p&gt;In today's highly competitive streaming landscape, where consumer attention spans are shorter than ever, and content is abundant, capturing and retaining audience interest is a monumental challenge. For businesses offering live sports or media streams, being able to cut through the noise and connect with consumers on a deeply personal level has become essential.&lt;/p&gt;

&lt;p&gt;Content personalization brings together multiple technologies to deliver rewards, experiences, and promotions that are tailored to the individual user. Traditional personalized experiences focused on predictable user patterns, for example, if they like a particular sports team, you could notify them that a stream containing their team is starting soon. Customer expectations are evolving, and the &lt;strong&gt;next step is being able to personalize content in real-time&lt;/strong&gt; based on user behavior or what is happening on stream, for example, fans are more likely to buy merchandise if their team is winning a game, so adapt your monetization strategy as the game evolves and help the customer feel more engaged with the stream and their team.&lt;/p&gt;

&lt;p&gt;Personalization works both ways. For consumers, it translates into a more relevant and enjoyable experience, reducing pain points, driving customer loyalty, and increasing viewer retention.&lt;/p&gt;

&lt;p&gt;How can you make audiences feel more involved in your livestream? How can you deliver personalized content such as real-time game stats or quizzes tailored to what is happening on stream? PubNub is here to help optimize your solution for your target audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delivering a Personalized Real-Time Experience to Your Audience
&lt;/h2&gt;

&lt;p&gt;You can't run before you can walk, so although it might seem obvious, I like to break the process down into 3 steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Gather data about your users and audience. Being open about what data you are collecting and &lt;strong&gt;why&lt;/strong&gt; you are collecting it will build trust between you and your customers. The more data you can gather, the greater your understanding of your audience will be, eventually enabling you to deliver more relevant content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Build a profile for each user. This step is all about giving context and meaning to the data you have already gathered. A user's viewing data can determine their favorite team, whether they typically watch on their phone, and which country or region they're from. As a viewer interacts with your stream, you can discover their preferred language, their friends, and how passionate they are about the current live event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Take personalized actions in real-time. This has traditionally been the “hard bit”, but PubNub is changing that. Let's say we are dealing with a sports stream, and one team scores - this is impossible to predict ahead of time but is a great moment to send some personalized engagement: perhaps send a poll targeting a specific demographic of people, or send them a promotion for targeted merchandise to celebrate their team's &lt;em&gt;predicted victory&lt;/em&gt;. You could even analyze the sentiment of chat messages within a stream, aggregate them using AI, and take action based on the emotion of the audience - even something as minor as showing a motivating animation to a disheartened user will help them feel engaged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Fe03c6dcee601457b994cb6d86f1a2f14" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Fe03c6dcee601457b994cb6d86f1a2f14" alt="3 Steps for personalizing real-time experiences" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Gather Data on User Behavior
&lt;/h3&gt;

&lt;p&gt;Every action your users take is data useful in understanding your audience. This is not a new concept, and you are already familiar with big data and predictive analytics solutions that can help you analyse your customer behavior “after the fact,” determine better what you should do “next time,” and create email marketing campaigns.&lt;/p&gt;

&lt;p&gt;As we start to think about content delivery and how to take real-time personalized actions for each user, it is useful to think of user behavior in two different ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Actions a user takes that help us learn more about that user and predict what they will do next time. This is the traditional “you might be interested in these live streams” approach that services, such as Netflix or Spotify, offer, and the more data users let you collect, the more personalized you can make content or product recommendations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Actions a user is taking right now: For example, are they online or offline? Which chat groups are they participating in? Are they happy or sad? Are they reacting to your stream? All of this customer data is critical to understand the type of personalized engagement that will resonate with them: It is the difference between sending an &lt;strong&gt;offline&lt;/strong&gt; user a mobile notification that their favorite team is playing soon, and incentivizing an &lt;strong&gt;online&lt;/strong&gt; user to participate in your live stream chat.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using PubNub, let's say you want to detect when a user goes online or offline, we refer to this as &lt;a href="https://www.pubnub.com/docs/general/presence/overview?" rel="noopener noreferrer"&gt;User Presence&lt;/a&gt; and it lets you know where your users are, and which streams they are currently watching in just a few lines of code. The most common platforms your users will be engaging with your streams are the web, either on mobile or desktop and native mobile apps for Android or iOS. With 50+ SDKs, PubNub has your platform covered, but let's look at the code you would use to detect when a user goes online or offline for those 3 platforms mentioned&lt;/p&gt;

&lt;p&gt;Users will subscribe to a &lt;code&gt;channel&lt;/code&gt; which represents the stream chat they are currently a member of, let's say the channel name is &lt;code&gt;football-stream&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript: Subscribing to a channel with presence&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//  High capacity chats should also consider the 'interval' event, &lt;/span&gt;
&lt;span class="c1"&gt;//  to determine presence changes since the last interval&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;football-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;receivePresenceEvents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onPresence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;join&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//  User has come online (football-stream channel)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leave&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
    &lt;span class="nx"&gt;presenceEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//  User has gone offline (football-stream channel)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Kotlin (Android): Subscribing to a channel with presence&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//  High capacity chats should also consider the 'interval' event, &lt;/span&gt;
&lt;span class="c1"&gt;//  to determine presence changes since the last interval&lt;/span&gt;
&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;football-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SubscriptionOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receivePresenceEvents&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;override&lt;/span&gt; &lt;span class="nx"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PubNub&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PNPresenceEventResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;If &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;join&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;//  User has come online (football-stream channel)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leave&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
      &lt;span class="nx"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;//  User has gone offline (football-stream channel)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Swift (iOS): Subscribing to a channel with presence&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//  High capacity chats should also consider the 'interval' event,&lt;/span&gt;
&lt;span class="c1"&gt;//  to determine presence changes since the last interval&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;football-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ReceivePresenceEvents&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onPresence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;presenceChange&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;presenceChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuids&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;//  uuids array have come online (football-stream channel)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuids&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;//  uuids array have gone offline (football-stream channel)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uuids&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;//  uuids array have gone offline (football-stream channel)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Build a Profile for Each User
&lt;/h3&gt;

&lt;p&gt;With data gathering in place, the next step is to build a profile for each user based on data-driven insights, which will, of course, update and improve the more that user interacts with your application and streams.&lt;/p&gt;

&lt;p&gt;Where should you store your user profiles? As mentioned in the first step, there are two types of data you want to keep track of: “traditional analytics” and “real-time actionable events”. You probably already have a platform in place for analytics and the great news is you can continue using your current platform AND still take advantage of real-time events generated by your users and captured through PubNub. PubNub's &lt;a href="https://www.pubnub.com/docs/serverless/events-and-actions/overview#actions?" rel="noopener noreferrer"&gt;Events &amp;amp; Actions&lt;/a&gt; platform allows you to select and filter events as they pass through the PubNub network, with matching events being forwarded to either &lt;a href="https://www.pubnub.com/docs/serverless/events-and-actions/actions/create-kinesis-action?" rel="noopener noreferrer"&gt;Amazon Kinesis&lt;/a&gt;, &lt;a href="https://www.pubnub.com/docs/serverless/events-and-actions/actions/create-kafka-action?" rel="noopener noreferrer"&gt;Apache Kafka&lt;/a&gt;, or a &lt;a href="https://www.pubnub.com/docs/serverless/events-and-actions/actions/create-webhook-action?" rel="noopener noreferrer"&gt;custom webhook&lt;/a&gt; allowing support for any platform. We also support bidirectional communication with Kafka using our &lt;a href="https://www.pubnub.com/developers/kafka/?" rel="noopener noreferrer"&gt;PubNub Kafka Bridge&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But what about profile data that is needed to make real-time decisions immediately? For example, a user's current mood, or their current level of engagement with your stream? &lt;a href="https://www.pubnub.com/docs/general/metadata/basics?" rel="noopener noreferrer"&gt;PubNub AppContext&lt;/a&gt; should be used to store information about your users and stream content, this might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The fan profile - their favourite team, whether they are currently typing a message, or their current mood. Fans, or stream participants are referred to as &lt;a href="https://www.pubnub.com/docs/general/metadata/users-metadata?" rel="noopener noreferrer"&gt;Users&lt;/a&gt; within PubNub AppContext.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The streams - which teams are playing, who is winning, or which artist is performing and which stage are they on. Streams are referred to as &lt;a href="https://www.pubnub.com/docs/general/metadata/channel-metadata?" rel="noopener noreferrer"&gt;Channels&lt;/a&gt; within PubNub AppContext.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The relationship between fans and streams—who is watching which stream, or which group of viewers has been watching the longest? PubNub AppContext captures these relationships as &lt;a href="https://www.pubnub.com/docs/general/metadata/membership-metadata?" rel="noopener noreferrer"&gt;Memberships&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an example of what you could do, let's take the following scenario to analyze user sentiment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A user is chatting and interacting with other users whilst watching one of your live streams.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user's messages are analysed in real-time to determine their sentiment - is this fan excited or disheartened at their team's performance?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The AppContext for this user is updated with their current 'mood'&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;This interaction would be trivial to implement using PubNub as follows:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analyzing user sentiment (1):&lt;/strong&gt; A user is chatting and interacting with other users in your live stream&lt;/p&gt;

&lt;p&gt;PubNub was designed to send and receive messages at scale, we are the world's largest event-driven network with less than 30ms global latency and an industry-leading 99.999% uptime. To help you build your chat solution, we have SDKs covering all popular languages, including dedicated &lt;a href="https://www.pubnub.com/docs/chat/overview?" rel="noopener noreferrer"&gt;Chat SDKs&lt;/a&gt; for JavaScript, Kotlin (Android), and Swift (iOS) making it trivial to incorporate chat alongside your streaming application.&lt;/p&gt;

&lt;p&gt;Using our Chat SDKs, you can quickly build a solution that features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Send and receive messages at scale, so participants can communicate regardless of how many people are watching the stream.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Live reactions, so fans can react immediately to what is happening on-stream as well as react to others' messages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moderation, allowing a safe and inclusive environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything that passes through our network is secure and compliant, we support message encryption, and we are &lt;a href="https://www.pubnub.com/trust/compliance/?" rel="noopener noreferrer"&gt;certified&lt;/a&gt; for SOC2, GDPR, CCPA, and ISO27001&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analyzing user sentiment (2):&lt;/strong&gt; The user's messages are analyzed in real-time to determine their sentiment&lt;/p&gt;

&lt;p&gt;PubNub exposes serverless &lt;a href="https://www.pubnub.com/docs/serverless/functions/overview?" rel="noopener noreferrer"&gt;Functions&lt;/a&gt;, allowing you to add custom logic as messages pass through our network. These Functions also support pre-built &lt;a href="https://www.pubnub.com/integrations/?" rel="noopener noreferrer"&gt;custom integrations&lt;/a&gt; with third-party services and APIs, including artificial intelligence or machine learning algorithms.&lt;/p&gt;

&lt;p&gt;So, for example, if you wanted to analyze a user's message sentiment in real time, your solution would look as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;User sends a chat message&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PubNub function detects that a message was sent and runs code asynchronously (we refer to this as an 'after publish' function, because it runs after the message is published to recipients)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A REST API call is made to an external service to analyse the message's sentiment, we support machine learning solutions (e.g. &lt;a href="https://www.pubnub.com/integrations/huggingface/?" rel="noopener noreferrer"&gt;HuggingFace&lt;/a&gt;), AI-powered automation (e.g. &lt;a href="https://www.pubnub.com/integrations/openai/?" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;), or dedicated content analysis solutions (e.g. &lt;a href="https://www.pubnub.com/integrations/tisane-labs-nlp/?" rel="noopener noreferrer"&gt;Tisane Labs&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The result of the REST API call can be stored as part of the user's profile.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The workflow would look something like this as a diagram. Of course, this is just an example of architecture, and Functions are very flexible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F62d8fe43d83a4b8f96e5190072906b97" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F62d8fe43d83a4b8f96e5190072906b97" alt="Analysing user message sentiment" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To learn more about how PubNub Functions can be used for sentiment analysis, including example code, please check out my recent blog, “&lt;a href="https://www.pubnub.com/blog/two-reasons-why-pub-nub-functions-are-awesome/#h-5?" rel="noopener noreferrer"&gt;Two reasons why PubNub Functions are Awesome&lt;/a&gt;”, where I covered this in more detail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analyzing user sentiment (3):&lt;/strong&gt; The AppContext for this user is updated with their current 'mood'&lt;/p&gt;

&lt;p&gt;To extend the previous example, once the user's message sentiment has been determined you can store this in AppContext. The Function execution environment exposes a &lt;a href="https://www.pubnub.com/docs/serverless/functions/functions-apis/pubnub-module#app-context?" rel="noopener noreferrer"&gt;PubNub module&lt;/a&gt; that can save data to and retrieve data from AppContext.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//  PubNub Function code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pubnub&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUUIDMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;//  ID of the user who sent the message&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;customFields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sentiment&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;positive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mood&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; 
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mood&lt;/span&gt;&lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;

  &lt;span class="c1"&gt;//  Store the updated mood back in AppContext&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setUUIDMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Set UUID metadata successfully.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt;      
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to set UUID metadata.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to fetch UUID metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Take Personalized Actions in Real-Time
&lt;/h3&gt;

&lt;p&gt;At this stage, you have a process in place to gather data about your stream viewers and are using that data to create and update their user profiles in real time. Let's look at some of the actions you can take to deliver highly personalized content, such as promotions or rewards that give tailored experiences based on fans’ behavior and preferences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If a user is offline, you could send them a mobile notification when a stream featuring their favorite sports team or music artist is about to start. Online fans would not receive this message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can enrich the streaming chat of live sports by adding polls or live commentary. Since sports are inherently unpredictable, you want to trigger a relevant poll only at the right moment during play.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You could alert the user immediately when their favorite team scores or a player is substituted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As real money gaming odds update, you could notify interested users when odds are particularly good for teams they regularly bet on - since every second counts when talking about gaming odds, PubNub's &amp;lt;30ms latency is critical.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.pubnub.com/products/illuminate-sports-media-entertainment/?" rel="noopener noreferrer"&gt;PubNub Illuminate&lt;/a&gt; is a powerful tool that lets you respond to events within the stream in real-time, and take actions based on both those events &amp;amp; the user's current profile.&lt;/p&gt;

&lt;p&gt;To extend the previous example, where we determined the user's current mood, let's assume the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The user, named Troy, is watching a live-streamed basketball game between the “Wildcats” and the “Knights”.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Troy supports the Wildcats, and as he watches the game, he sends messages using the stream chat. Based on the content of these messages, his 'mood' is assigned a numeric value as described in the previous step.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Troy's mood will be tracked in PubNub AppContext as part of his User metadata&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The current game score will be tracked in PubNub AppContext as part of the Channel metadata&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The scenario is as follows:&lt;/strong&gt; You want to run a promotion targeted at Wildcats fans. Specifically, if the team is dominating its rivals, you want to offer any high-spirited users who are in a good mood an opportunity to celebrate by buying some themed merchandise.&lt;/p&gt;

&lt;p&gt;Using PubNub Illuminate, you could set up a “Business Object” as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Faa302294b5344381bc770cceb49f1dc8" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Faa302294b5344381bc770cceb49f1dc8" alt="PubNub Illuminate Business Object" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;“Business Objects” define what you want to track, specifically I have defined the user's mood, their favorite team and the current team scores. Notice that the user's mood and favorite team are mapped to &lt;code&gt;$.user.custom.mood&lt;/code&gt; and &lt;code&gt;$.user.custom.favorite_team&lt;/code&gt;, so are pulled from User AppContext. Similarly, the Wildcats team score is pulled from Channel AppContext, &lt;code&gt;$.channel.custom.wildcatsScore&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Business Object will monitor these data fields, calculate any metrics, determine whether any decisions need to be evaluated, and present the data on any defined Dashboards.&lt;/p&gt;

&lt;p&gt;The metric will calculate the average mood of Wildcat fans as they send chat messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Fabfe07a9d0d74ef994e4c467778bc7d5" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252Fabfe07a9d0d74ef994e4c467778bc7d5" alt="PubNub Illuminate Metric" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the filter to only evaluate this metric for Wildcats fans, remember the favorite team is stored in PubNub AppContext and forms part of our user profile. If new users join the stream, and declare themselves Wildcats fans (or you infer it from their behavior and update their profile automatically), then they will automatically be included in this metric. Filters can also allow a degree of A/B testing, breaking down viewers into audience segments to test customer engagement.&lt;/p&gt;

&lt;p&gt;The metric will be evaluated whenever a user sends a message, so it is the mood of &lt;strong&gt;actively participating chat users&lt;/strong&gt;, weighted towards those users sending more messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F76208002b71e428e8af91eb2a2b8f7eb" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F76208002b71e428e8af91eb2a2b8f7eb" alt="PubNub Illuminate Dashboard" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dashboard will display that average user mood, updating in real-time, so you can visualize your audience's mood as the live stream progresses.&lt;/p&gt;

&lt;p&gt;The red bars on the graph indicate whenever a 'Decision' was made, so let’s look at that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F91cba99efb4e423fa15bbd0c2934be6b" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F91cba99efb4e423fa15bbd0c2934be6b" alt="PubNub Illuminate Decision" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, the goal is to send spirited users who are in a good mood a merchandise promotion if their team is outperforming their rivals.&lt;/p&gt;

&lt;p&gt;The decision defines the scenario we want to capture, in this case, we detect whether the user is a Wildcat fan and the Wildcats have scored over 90 points, whilst their rivals are languishing below 60. The user's mood must also be greater than '10' - remember this is an arbitrary value we have assigned based on the sentiment of the user's messages they are sending in the stream chat.&lt;/p&gt;

&lt;p&gt;If all the conditions in the decision evaluate to true, then the “Send Happy User Promotion” action is performed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For testing&lt;/strong&gt;, I am sending a PubNub Message back to the user on the same channel used for chat, &lt;code&gt;game01&lt;/code&gt; in this case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F61b994ad85044338a0bacbeffd959aa0" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F61b994ad85044338a0bacbeffd959aa0" alt="PubNub Illuminate Action" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Testing using the PubNub debug console (part of the &lt;a href="https://admin.pubnub.com/?" rel="noopener noreferrer"&gt;admin portal&lt;/a&gt;), and having previously defined the user's mood and team score using AppContext, the action can be successfully triggered:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F91cba99efb4e423fa15bbd0c2934be6b" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pubnub.com%2Fcdn%2Fb%2Fapi%2Fv1%2Fimage%2Fassets%252F0ee4d50ccdc943eda308d1099e2b1915%252F91cba99efb4e423fa15bbd0c2934be6b" alt="PubNub Illuminate - Testing with Send Message" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In production, instead of sending a test message, you would expose a custom webhook in your server application, which would be called by PubNub Illuminate whenever a user needs to be sent a promotion. As you can see from the test message, the user ID, their mood score and their favorite team have been included which should be enough detail to email the user a promotion link, but Illuminate is very flexible and any data fields you define in your “Business Object” can also be included in the webhook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a Digital Marketing Strategy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How can personalized marketing improve customer satisfaction? By using a combination of dynamic content, customer preferences, and personalization strategies, you can develop social media campaigns, email campaigns, and landing pages/homepages tailored to a specific audience. This is the power of personalization; by taking a user’s individual preferences and past purchases into account with real-time actions, you can enhance their customer experience. Understand potential customers better by looking at the specific needs of your current customers and considering their customer journey: what is their purchase history? Or browsing history on your site? Let user data collection inform your content marketing: What delivers the most engaging experience for your customer? Which calls to action give the best click-through rates and drive higher engagement? Rather than wait until after the event concludes, you can now get valuable insights into the user experience in real time and adjust your content strategy accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;By personalizing your streaming content for individual customers and making the experience interactive for your viewers, you can increase viewer retention and conversion rates, boost brand loyalty, and increase market share. By making user interactions real-time, you can take advantage of opportunities for monetization that you could not have foreseen prior to the sports event or media stream starting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.pubnub.com/solutions/sports-media/?" rel="noopener noreferrer"&gt;Learn more&lt;/a&gt; about PubNub can help with your live sports, streaming &amp;amp; fan engagement solution; &lt;a href="https://www.pubnub.com/company/contact-sales/?" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt;, or sign up for a &lt;a href="https://admin.pubnub.com/register?" rel="noopener noreferrer"&gt;free PubNub account&lt;/a&gt; to explore how you can tailor content for your audience in real-time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.builder.io%2Fapi%2Fv1%2Fpixel%3FapiKey%3D0ee4d50ccdc943eda308d1099e2b1915" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.builder.io%2Fapi%2Fv1%2Fpixel%3FapiKey%3D0ee4d50ccdc943eda308d1099e2b1915" width="1" height="1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How can PubNub help you?
&lt;/h1&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://www.pubnub.com/blog/deliver-personalized-content-promotions-and-rewards-tailored-to-your-audience/?" rel="noopener noreferrer"&gt;PubNub.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our platform helps developers build, deliver, and manage real-time interactivity for web apps, mobile apps, and IoT devices.&lt;/p&gt;

&lt;p&gt;The foundation of our platform is the industry's largest and most scalable real-time edge messaging network. With over 15 points-of-presence worldwide supporting 800 million monthly active users, and 99.999% reliability, you'll never have to worry about outages, concurrency limits, or any latency issues caused by traffic spikes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience PubNub
&lt;/h2&gt;

&lt;p&gt;Check out &lt;a href="https://www.pubnub.com/tour/introduction/?" rel="noopener noreferrer"&gt;Live Tour&lt;/a&gt; to understand the essential concepts behind every PubNub-powered app in less than 5 minutes&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Setup
&lt;/h2&gt;

&lt;p&gt;Sign up for a &lt;a href="https://admin.pubnub.com/signup/?" rel="noopener noreferrer"&gt;PubNub account&lt;/a&gt; for immediate access to PubNub keys for free&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.pubnub.com/docs?" rel="noopener noreferrer"&gt;PubNub docs&lt;/a&gt; will get you up and running, regardless of your use case or &lt;a href="https://www.pubnub.com/docs?" rel="noopener noreferrer"&gt;SDK&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Documentation Release Notes - January 2025</title>
      <dc:creator>PubNub Developer Relations</dc:creator>
      <pubDate>Tue, 04 Feb 2025 17:47:48 +0000</pubDate>
      <link>https://dev.to/pubnub/documentation-release-notes-january-2025-583g</link>
      <guid>https://dev.to/pubnub/documentation-release-notes-january-2025-583g</guid>
      <description>&lt;p&gt;This article was originally published at &lt;a href="https://www.pubnub.com/docs/release-notes/2025/january?" rel="noopener noreferrer"&gt;https://www.pubnub.com/docs/release-notes/2025/january&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're kicking off the year with quite a few interesting documentation changes.&lt;/p&gt;

&lt;p&gt;We've revamped the keyset configuration experience for easier access, introduced message drafts in gaming chat SDKs, and added event-based decisions in Illuminate.&lt;/p&gt;

&lt;p&gt;Plus, we've got new features in the client-side mute list, message reactions in the PHP SDK, and more intuitive advanced presence settings in the BizOps Workspace.&lt;/p&gt;

&lt;p&gt;Let's dive into the details!&lt;/p&gt;

&lt;h2&gt;
  
  
  General 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New keyset configuration experience
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;This month, we completely revamped the &lt;a href="https://pubnub.com/docs/general/portal/keysets" rel="noopener noreferrer"&gt;keyset&lt;/a&gt; creation process on the &lt;a href="https://admin.pubnub.com?" rel="noopener noreferrer"&gt;Admin Portal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Creating an app and a set of keysets is one of the initial steps if you want to start exploring PubNub. These keysets enable secure and controlled access to PubNub's real-time messaging capabilities, ensuring that only authorized users can publish or subscribe to channels in your app.&lt;/p&gt;

&lt;p&gt;Until now, when you created keysets, you often didn't even know what configuration they had until you stumbled upon an obstacle in your app and could not use features like Presence or App Context. Only then did you explore the keyset's configuration and look for proper setup options.&lt;/p&gt;

&lt;p&gt;Until now, keysets were created with a default configuration that turned off most options. We decided to expose keyset configuration more and let you make a deliberate decision about which configuration option to enable at the very initial step of keyset creation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6xfdpbsytm5lrzjxcl0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6xfdpbsytm5lrzjxcl0.png" alt="Keyset configuration" width="800" height="729"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating a keyset, you can still return to the Admin Portal and change your mind about enabled features.&lt;/p&gt;

&lt;p&gt;We hope this change will let you spend less time on configuration and makes it easier for you to get started quickly with PubNub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyset number limit
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Adjustment&lt;/p&gt;

&lt;p&gt;This month we also worked on updating our policy regarding &lt;a href="https://pubnub.com/docs/general/portal/keysets" rel="noopener noreferrer"&gt;keyset&lt;/a&gt; access to free accounts.&lt;/p&gt;

&lt;p&gt;For optimization reasons, we decided to limit the number of keysets you can have at once on a free account to a maximum of 3.&lt;/p&gt;

&lt;p&gt;If your account exceeds this limit, you must delete existing keysets to create new ones.&lt;/p&gt;

&lt;p&gt;This change is effective as of &lt;strong&gt;February 3&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Whitelisting IPs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Improvement&lt;/p&gt;

&lt;p&gt;Following your feedback, we updated the docs to include information on how you can &lt;a href="https://pubnub.com/docs/general/setup/account-setup" rel="noopener noreferrer"&gt;allow traffic&lt;/a&gt; to specific domains (and subdomains) associated with PubNub (e.g., &lt;code&gt;*.pubnub.com&lt;/code&gt;, &lt;code&gt;*.pndsn.com&lt;/code&gt;) if your firewall blocks them.&lt;/p&gt;

&lt;p&gt;You can typically whitelist domains by configuring your firewall or network settings to allow traffic to and from those domain names.&lt;/p&gt;

&lt;p&gt;However, suppose your firewall system or network configuration does not support domain-based rules and requires IP addresses instead. In that case, you can contact &lt;a href="https://support.pubnub.com/hc/en-us/requests/new?" rel="noopener noreferrer"&gt;PubNub support&lt;/a&gt; to get the complete list of PubNub Network IP addresses for whitelisting.&lt;/p&gt;

&lt;p&gt;This option is available only for customers on paid plans.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Improvement&lt;/p&gt;

&lt;p&gt;Following another round of feedback, we summarized information on how PubNub lets you monitor real-time activities and diagnose issues effectively in your apps by configuring logging for your apps.&lt;/p&gt;

&lt;p&gt;Most PubNub SDKs provide configuration options to enable and control the level of logging output.&lt;/p&gt;

&lt;p&gt;Read the &lt;a href="https://pubnub.com/docs/general/setup/logging" rel="noopener noreferrer"&gt;Logging&lt;/a&gt; document for details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom domains
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Improvement&lt;/p&gt;

&lt;p&gt;There is a number of reasons for which you might want to have your own domain name for your PubNub-based apps, including unique branding, compliance and control, or improved traffic management.&lt;/p&gt;

&lt;p&gt;PubNub lets paid customers set up custom application domain names to access PubNub’s real-time messaging infrastructure instead of the default PubNub endpoint &lt;code&gt;ps.pndsn.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For details on the process, refer to &lt;a href="https://pubnub.com/docs/general/setup/data-security#custom-domain" rel="noopener noreferrer"&gt;this instruction&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDKs 📦
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Message drafts in gaming chat SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;This month brought another round of support for message drafts in Chat SDKs by adding this functionality to our gaming SDKs: &lt;a href="https://pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/drafts" rel="noopener noreferrer"&gt;Unreal Chat SDK&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/drafts" rel="noopener noreferrer"&gt;Unity Chat SDK&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Unreal&lt;/li&gt;
&lt;li&gt;  Unity
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Assuming you have a valid UPubnubChannel* pointer named Channel&lt;/span&gt;

&lt;span class="c1"&gt;// Define a configuration for the message draft if needed (using default configuration here)&lt;/span&gt;
&lt;span class="nx"&gt;FPubnubMessageDraftConfig&lt;/span&gt; &lt;span class="nx"&gt;DraftConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This might include settings like initial content or behaviors&lt;/span&gt;

&lt;span class="c1"&gt;// Create a message draft from the channel with the specified configuration&lt;/span&gt;
&lt;span class="nx"&gt;UPubnubMessageDraft&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;MyMessageDraft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Channel&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;CreateMessageDraft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DraftConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Now MyMessageDraft can be used to build and send messages&lt;/span&gt;
&lt;span class="nx"&gt;MyMessageDraft&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;InsertText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello there! Please review and confirm.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;MyMessageDraft&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;messageDraft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateMessageDraft&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we can proudly announce that we now support message drafts in all Chat SDKs. 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  Client-side mute
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;We added the client-side mute list to the Chat object in the &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/moderation-user" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt; and &lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/features/users/moderation-user" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt; Chat SDKs. This new feature lets users mute other users on all channels and, as a result, stop seeing all messages and events originating from the muted users.&lt;/p&gt;

&lt;p&gt;The new feature also lets you unmute muted users and retrieve a list of all users you muted on a given channel.&lt;/p&gt;

&lt;p&gt;You also get the new configuration option (&lt;code&gt;syncMutedUsers&lt;/code&gt; parameter) to automatically synchronize the mute list across sessions and devices using a specific App Context User object.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Kotlin&lt;/li&gt;
&lt;li&gt;  JavaScript
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Chat&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChatConfiguration&lt;/span&gt;

&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;ChatConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;publishKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;subscribeKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myUniqueUserId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;userToMute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_1905&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mutedUsersManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;muteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userToMute&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Chat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@pubnub/chat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;publishKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subscribeKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myUniqueUserId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userToMute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_1905&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mutedUsersManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;muteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userToMute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Message reactions in PHP SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;Not to lag behind other SDKs, the PHP SDK finally supports the &lt;a href="https://pubnub.com/docs/sdks/php/api-reference/message-actions" rel="noopener noreferrer"&gt;Message Reactions API&lt;/a&gt;, letting you add, remove, and get the list of reactions in a given channel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$messageAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PNMessageAction&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reaction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;drooling_face&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messageTimetoken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$messageTimetoken&lt;/span&gt; &lt;span class="c1"&gt;// the timetoken of the message you want to add the reaction to&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nx"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$pubnub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addMessageAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pizza_talks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;messageAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$messageAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Migration guide for JavaScript SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Since some of our clients were having difficulty using our JavaScript SDK after migrating from v7 to v8, we decided to create a &lt;a href="https://pubnub.com/docs/general/resources/migration-guides/js-v7-v8-migration-guide" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt; to list changes you need to perform in your app code for the SDK to work as expected.&lt;/p&gt;

&lt;p&gt;These include removing the &lt;code&gt;@types/pubnub&lt;/code&gt; package dependency, as the types are now included within the SDK, and updating your import statements for PubNub types to align with the new endpoint groupings in version 8.0.0, such as &lt;code&gt;AppContext.GetMembershipsParameters&lt;/code&gt;, ensuring your code references are updated to reflect these structured namespaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom message type (follow-up)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;As a &lt;a href="https://pubnub.com/docs/release-notes/2024/december#custom-message-type-follow-up" rel="noopener noreferrer"&gt;follow up&lt;/a&gt;, we added support for the custom message type parameter in the Ruby SDK in the following APIs: Publish, Subscribe, and Message Persistence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pubnub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_channel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;custom_message_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nx"&gt;puts&lt;/span&gt; &lt;span class="nx"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;
&lt;span class="nx"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Membership type (follow-up)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;To follow up on &lt;a href="https://pubnub.com/docs/release-notes/2024/december#membership-type" rel="noopener noreferrer"&gt;last month's updates&lt;/a&gt; in a few SDKs, we added support for the membership type in the Ruby SDK to let you categorize memberships more easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Changelogs in Chat SDKs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Addressing documentation debt, the &lt;a href="https://pubnub.com/docs/chat/chat-sdk/build/changelog" rel="noopener noreferrer"&gt;JavaScript Chat SDK&lt;/a&gt;, &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk/build/changelog" rel="noopener noreferrer"&gt;Kotlin Chat SDK&lt;/a&gt;, and &lt;a href="https://pubnub.com/docs/chat/swift-chat-sdk/build/changelog" rel="noopener noreferrer"&gt;Swift Chat SDK&lt;/a&gt; now include changelogs so you can track in detail what a new SDK version adds, removes, or updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Utility methods in Kotlin Chat SDK
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;Kotlin Chat SDK now has a &lt;a href="https://pubnub.com/docs/chat/kotlin-chat-sdk/build/features/utility-methods" rel="noopener noreferrer"&gt;document&lt;/a&gt; listing utility methods for converting PubNub timetokens to and from dates, UNIX timestamps, and Instant objects. This enables you to display or manipulate date and time information in a human-readable format or align it with other systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  BizOps Workspace 🏢
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Advanced presence settings
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;This month, we got down to the &lt;a href="https://pubnub.com/docs/bizops-workspace/presence-management" rel="noopener noreferrer"&gt;Presence Management&lt;/a&gt; section in BizOps Workspace.&lt;/p&gt;

&lt;p&gt;We changed the UI by exposing the more advanced presence settings, which let you decide whether to track &lt;strong&gt;Subscribe Heartbeats&lt;/strong&gt; or &lt;strong&gt;Presence Heartbeats&lt;/strong&gt; on a given channel or channel pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkuo4p2lbw8wkygszl8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkuo4p2lbw8wkygszl8o.png" alt="Advanced presence settings" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While &lt;strong&gt;Subscribe Heartbeats&lt;/strong&gt; define how long the server considers the client alive for presence to ensure that the client does not lose its subscription to a channel due to inactivity, &lt;strong&gt;Presence Heartbeats&lt;/strong&gt; specify how often the client will send heartbeat signals to the server, offering more granular control over client activity tracking than &lt;strong&gt;Subscribe Heartbeats&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While Presence Management lets you decide which of them you want to track (one of them is required for any presence rule to be enabled on a channel), you enable/configure both during your SDK initialization (through &lt;code&gt;presenceTimeout&lt;/code&gt; and &lt;code&gt;heartbeatInterval&lt;/code&gt; settings).&lt;/p&gt;

&lt;h2&gt;
  
  
  Illuminate 💡
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Event-based Decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: New feature&lt;/p&gt;

&lt;p&gt;Until now, you were only able to create Decisions in Illuminate based on aggregations (metrics), This means that a specified calculation, like max, average or sum of events, had to be reached to trigger an action in a Decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh83o48hglbwfwy2tx3kc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh83o48hglbwfwy2tx3kc.png" alt="Event-based decisions" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now added an event trigger to actions, letting you trigger actions each time a given event is detected.&lt;/p&gt;

&lt;p&gt;For example, a metric-based decision would activate dynamic pricing when the average number of orders is greater than 30, while in an event-based decision, coins can be given as soon as a participant joins an online show.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI improvements in Decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: Enhancement&lt;/p&gt;

&lt;p&gt;While working on event-based Decisions, we also tweaked the UI for Decisions, adding more clarification on why you must choose a Business Object to start with and let you more intuitively select publish and subscribe keys for an action (automated choice instead of manually pasting the values).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczggj8ffw2u92xtjvg64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczggj8ffw2u92xtjvg64.png" alt="Conditions" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3innajr5yzf8964ke6qp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3innajr5yzf8964ke6qp.png" alt="Keyset selection" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pubnub</category>
      <category>documentation</category>
      <category>releases</category>
      <category>releasenotes</category>
    </item>
  </channel>
</rss>
