---
source_url: https://www.pubnub.com/docs/entertainment/automated-media/real-time-advertising-and-updates
title: Real-time advertising and updates
updated_at: 2026-05-22T11:04:47.581Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Real-time advertising and updates

PubNub enables real-time analytics and automated customer-behavior-driven decisioning for live sports applications, creating dynamic experiences that adapt instantly to fan engagement and how they interact with your application.

By the end of this document, you will:

* Learn how to implement automated emoji upgrades based on user behavior
* Get to know how to serve dynamic ads based on user sentiment
* Understand how to trigger dynamic polls based on user reactions and engagement
* Discover how to track real-time analytics and make automated content decisions

## How PubNub helps

| Role in the solution | PubNub feature (click to learn more!) |
| --- | --- |
| Track user engagement in real time | [Pub/Sub](https://www.pubnub.com/docs/general/messages/publish) |
| Trigger polls and surveys based on user engagement, Upgrade emojis based on reaction thresholds, React to user behavior in real-time to provide targeted ads | [PubNub Illuminate](https://www.pubnub.com/docs/illuminate/basics) |

## Use case overview

The [Live Events](https://pn-solution-live-events.netlify.app/popout) demo shows how you can respond to user behavior in real-time. By targeting specific milestones in your app, you automate actions to enhance the user experience and monetize engagement by unlocking additional features for active users or offering incentives before they disengage.

The demo will take action based on the following user behavior:

* Triggers: The demo uses emoji reactions (😡, 🎉) as triggers, but you could also trigger actions based on chat mentions, poll participation, or any custom user behavior you want to track. More about triggersFor information on automatically triggering polls based on user reactions, refer to Automated polling.
* Processing: The demo aggregates emoji reactions over a 60-second window, but you could also process events immediately (like responding to a mention) or implement custom processing logic based on your needs.
* Actions: When triggers are processed, the demo shows automated actions like displaying a custom poll ("Which team is playing the dirtiest?"), but you could also trigger emoji upgrades, dynamic ads, or any custom response you define.

:::tip See it in action
Notice in the clip below how the 🔥 emoji changes to 😎 and the "Time to unwind?" ad appears when the user gets increasingly frustrated.
:::

Your browser does not support the video tag.

## Basic setup for automated decisioning

The Live Events demo uses [PubNub Illuminate](https://www.pubnub.com/docs/illuminate/basics) to trigger emoji upgrades, polls, and dynamic ads based on user behavior.

PubNub Illuminate is designed to enhance real-time applications by providing advanced analytics and automated decision-making capabilities without changing the application code.

It allows product managers to create dynamic user experiences by reacting to user engagement and behavior in real-time. With Illuminate, you can trigger actions such as polls, surveys, and targeted advertisements based on user interactions, ensuring that content is always relevant and engaging.

Before you can leverage the powerful features of PubNub Illuminate for real-time analytics and automated decision-making, ensure the following prerequisites are met:

| Prerequisite | Description |
| --- | --- |
| PubNub account | You must have an active PubNub account. If you don't have one, you can sign up on the [Admin Portal](https://admin.pubnub.com/). |
| Any PubNub SDK | Your app must use a [PubNub SDK](https://www.pubnub.com/docs/sdks). This is essential for connecting your app to the PubNub network and utilizing Illuminate's capabilities. |
| Illuminate subscription | Ensure that your PubNub pricing plan includes Illuminate. For more information, refer to [PubNub Pricing](https://www.pubnub.com/pricing). |

:::tip SDK configuration
You can use [any PubNub SDK](https://www.pubnub.com/docs/sdks) to implement this solution. For optimal performance and security:
* Use unique user IDs for each user, but reuse it for different client devices ( mobile, tablet, via browser) of the same user.
* Keep your publish and subscribe keys secure.
* Consider using environment variables for sensitive data.
For more information on available configuration options, refer to the [Configuration](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration) documentation of the SDK you're using. The [Live Events](https://pn-solution-live-events.netlify.app/popout) demo app uses the JavaScript SDK [via the JavaScript Chat SDK](https://www.pubnub.com/docs/chat/chat-sdk/build/configuration#additional-configuration-options), which provides chat-specific methods as well as the [core JavaScript SDK](https://www.pubnub.com/docs/sdks/javascript) operations, but that's not important to illustrate how automated decisioning works.
:::

## Emoji upgrades and dynamic ads

In the Live Events demo, there are two realtime decisions triggered by user behavior:

* Emoji upgrades - when a user taps an emoji more than 10–20 times in 60 seconds, Illuminate triggers an upgrade to a more expressive emoji, for example: 😢 upgrades to 😭 or 😡 to 🤬.
* Dynamic ads - when a user taps the 😡 emoji more than 20 times in 60 seconds, Illuminate triggers a "Time to unwind?" ad because the user is clearly frustrated.

This shows how an app can take custom actions based on user behavior in real-time.

### Track emoji taps

When a user taps an emoji (e.g., 😡), a message is published to a dedicated channel (e.g., `game.stream-reactions`) with the following data:

```javascript
async function emojiClicked(emoji) {
  if (!chat) return
  await chat.sdk.publish({
    message: { text: `${emoji}`, type: 'reaction' },
    channel: streamReactionsChannelId
  })
}
```

Depending on the emoji tapped, the app reacts differently. In this case, we use the 😡 emoji tap as an indicator of frustration, but you can use any behavior you want to track and react to. When the user clicks other emojis, the app recognizes the behavior and triggers the appropriate action - changing the emoji to a heart or upgrading the emoji.

### Configure Illuminate

Now that we have a steady stream of data on the `game.stream-reactions` channel, we can configure Illuminate to trigger the emoji upgrade based on the user's behavior.

Illuminate consists of these modules:

* [Business Object](https://www.pubnub.com/docs/illuminate/business-objects/basics) – how you get data into Illuminate. Business Objects are containers for capturing data from the selected apps and keysets. You can add and define ([data fields](https://www.pubnub.com/docs/illuminate/business-objects/basics#data-fields), create [metrics](https://www.pubnub.com/docs/illuminate/business-objects/basics#metrics)) with the desired aggregation, and activate Business Objects to start the data capture process.
* [Decision](https://www.pubnub.com/docs/illuminate/decisions/basics) – where you take action on the metrics you've created. You can do that by defining [rules](https://www.pubnub.com/docs/illuminate/decisions/basics#rules) with [conditions](https://www.pubnub.com/docs/illuminate/decisions/basics#conditions) to be met, and [actions](https://www.pubnub.com/docs/illuminate/decisions/basics#actions) triggered whenever these rules are met.
* [Dashboard](https://www.pubnub.com/docs/illuminate/dashboards/basics) – where you visualize the metrics you've created in Business Objects and actions executed in Decisions through [charts](https://www.pubnub.com/docs/illuminate/dashboards/basics#charts) and [dashboards](https://www.pubnub.com/docs/illuminate/dashboards/basics#dashboards) (collections of charts).

![Illuminate — building blocks](https://www.pubnub.com/assets/images/illuminate-building-blocks-a3e8e52563c889f9ad7d88bf9959a8e4.png)

Let's start with creating a Business Object.

### Create a Business Object

In Illuminate, the first thing to do is create a business object. You can see what the business object looks like in detail in the Demo Admin portal account [here](https://demo-admin.pubnub.com/user/627747/account/632313/illuminate/business-objects/877ad0c9-20ce-4927-8cc6-6a19464719b4).

![Business Object](https://www.pubnub.com/assets/images/business-object-f1c0229800d8884ca14b229eb87b6b32.png)

When you create a new business object, you must attach it to an app and keyset and map the data fields to the events you want to track. For detailed information on creating business objects, refer to [Create Business Object](https://www.pubnub.com/docs/illuminate/business-objects/create-business-object#steps). In the meantime, inspect the business object that the Live Events demo uses.

![Data fields](https://www.pubnub.com/assets/images/data-fields-d79dafc7337062554d67e35dfde7621c.png)

| Field Name | Mapped From | Type | Description |
| --- | --- | --- | --- |
| Reaction | `$.message.body.text` | String | This is the emoji or user reaction content. It captures the emoji tapped by the user, providing insight into user interactions and preferences. |
| Channel | `$.message.channel` | String | This captures the channel name on which the message was sent. |
| MessageType | `$.message.body.type` | String | This is always `reaction` in the Live Events demo, but if you are sending multiple message types on the same channel, you can filter them by this field. |

You can use the data fields for conditional logic, but more on that later. For now, let's focus on what we want to track.

### Create metrics

By defining specific metrics, product managers can tailor the user experience to be more responsive and engaging, ensuring that the application reacts to user behavior in meaningful ways. For detailed information on creating metrics, refer to [Create Metric](https://www.pubnub.com/docs/illuminate/business-objects/create-business-object#create-metrics).

![Metric](https://www.pubnub.com/assets/images/metric-588142b3f47c6b112a1a01ecc982c7f8.png)

In the Live Events application, the **Count of Reactions in a Minute** metric tracks how many user reactions (emoji taps) occur in a specific channel, filtered by message type and evaluated every minute. It's used to power decisions such as emoji upgrades, dynamic ads, and live polls.

| Field | Value | Description |
| --- | --- | --- |
| Name | Count of Reactions in a Minute | Human-readable name for the metric, used in dashboards and decisions. |
| Function | `COUNT` | Aggregation function that counts the number of messages matching the filter during each evaluation period. |
| Measure | None | No custom numeric field is being measured (e.g., summing a value). The metric just counts the number of matching events. |
| Period | 1 minute | The aggregation window. Messages are counted over a rolling one-minute period. |
| Filter | `Channel` Equals `game.stream-reactions` `MessageType` Equals `reaction` | Filters incoming PubNub messages to only include messages of type `reaction` sent on the `game.stream-reactions` channel. |
| Dimensions | `Reaction`, `Channel`, `MessageType` | Fields used to group the metric data. Allows the count to be tracked separately for each unique emoji (reaction), channel, and message type. |
| Used in Decisions | Emoji Upgrades & Ads | This metric triggers downstream Illuminate Decisions that perform actions like upgrading emojis or launching dynamic content (e.g., polls). |
| Used in Dashboards | Live Events | This metric is also used in the Showcase: Live Events dashboard for monitoring and visualizing reaction activity in real-time. |

To start capturing and storing the data, you must activate the business object.

### Activate the Business Object

When you click the **Activate** button, Illuminate starts capturing the emoji taps until you deactivate or delete the business object. You can't add or remove data fields once you've activated a business object, but you can add a metric to it.

Data you defined in business objects and subsequently captured are housed in a single database for 90 days.

With the business object that is configured and active, you can create a decision or a dashboard.

##### Before you activate

To work effectively with Business Objects, mind the following:

* To create and save a Business Object, you must define at least one data field. However, you must create at least one metric to use the Business Object in a chart. Once saved, you can create a metric and/or a query.
* For a Business Object to start capturing and storing the data based on the information provided, you must activate it. To activate a Business Object, all data fields must be [mapped](https://www.pubnub.com/docs/illuminate/business-objects/basics#data-mapping) and you must have at least one app & keyset selected.
* You can either first activate a Business Object or create a Metric or a Query for it — the order doesn't matter.
* Once you activate the Business Object: Illuminate starts capturing the defined data., You can add a metric to it or create a query., You can edit a metric in this Business Object if it's not used in an active Decision., You can edit a query that sources data from this Business Object if it's not used in an active Decision., You can still change the JSON paths mapped for data fields., You cannot add any more data fields to this Business Object.
* You can deactivate the Business Object if you no longer need it. When you deactivate a Business Object, the data defined in it is no longer captured. If you reactivate the Business Object, the data will start flowing anew, but you must account for the data gap between the deactivation and reactivation periods.
* When you delete the Business Object, it's permanent, and you cannot undo this action. Any Decisions and charts within Dashboards that use this deleted Business Object will get automatically deleted.

### Create a decision

Decisions are the core of Illuminate. They are triggered by metrics and contain rules that define the conditions for actions to be executed. You can see the decision in detail in the Demo Admin portal account [here](https://demo-admin.pubnub.com/user/627747/account/632313/illuminate/decisions/5fc334e8-480e-4d65-94b2-aa6cffd89a0a).

##### More on decisions

Once you create a Business Object, you can evaluate data, monitor trends, and act on results.

Illuminate includes the Decisions module. Decisions can be based on a query, a metric or the events from a Business Object. You define what to act on by choosing metrics, queries or events, configuring actions, and adding rules that control when actions run.

When creating a Decision, you:

1. Choose a Query or a Business Object along with a linked metric or event if a Business Object is selected. For asset tracking, use Hours since order (Number) and Trailer ID (String).
2. Define [actions](https://www.pubnub.com/docs/illuminate/decisions/basics#actions). For example, notify a transportation manager when a delivery is delayed.
3. Set [rules](https://www.pubnub.com/docs/illuminate/decisions/basics#rules) with conditions and actions. For example, trigger a notification only when goods are 2 hours late or more.

Decisions help product managers test engagement and monetization strategies before deployment. With Illuminate, you use real data instead of assumptions and act through automated conditions and actions.

The Live Events demo has a single decision to trigger an emoji upgrade when a user taps any emoji more than the specified number of times (with one exception) in a minute and an ad when a user taps the 😡 emoji more than 20 times in one minute.

![Decision](https://www.pubnub.com/assets/images/decision-c2b0a6d0f405699824fd7961c7b5df40.png)

Each decision must have at least one associated condition and action. The Live Events demo has three actions:

| Action | Description |
| --- | --- |
| Showcase: Live Event Upgrade Emoji to Default | Upgrades the emoji to a more expressive one. |
| Showcase: Live Event Upgrade Emoji to Heart | Upgrades the upgraded emoji to a heart. As opposed to the **Showcase: Live Event Upgrade Emoji to Default** action, this action can override the emoji in the client app code. That's the exception we mentioned earlier. |
| Showcase: Live Event Show Dynamic Ad | Displays a dynamic ad. |

#### Live event upgrade emoji to default

The **Showcase: Live Event Upgrade Emoji to Default** action upgrades the emoji to a more expressive one when the user taps the emoji more than the specified number of times in a minute.

In the Live Events demo, this is triggered when the user taps any emoji more than 20 times in one minute. This action publishes a message to the `illuminate-upgrade-reaction` channel with the following payload:

```json
{
  "emoji": "${Reaction}",
}
```

The emoji is defined as `${Reaction}` because, in your Illuminate metric, you map incoming fields from PubNub messages to named fields so you can use them later. Remember when we mapped `reaction` to `$.message.body.text` during the [Create a Business Object](#create-a-business-object) step? This is how we can use the actual emoji tapped by the customer in the Illuminate decision.

:::note How the demo handles emoji upgrades
In the demo, Illuminate doesn't publish upgraded emojis. Instead, it notifies the client that the emoji has been upgraded by publishing a message, and the client handles the display using an `emojiMap` object that maps emojis to their upgraded versions. You can find more details on the demo's implementation in [Listen for triggers and react](#listen-for-triggers-and-react).
Illuminate is flexible and you can configure it to handle emoji upgrades in different ways, like directly publishing the upgraded emoji, or triggering any other custom action you define.
:::

#### Live event upgrade emoji to heart

The **Showcase: Live Event Upgrade Emoji to Heart** action upgrades the 😮 emoji to a heart.

In the Live Events demo, this is triggered when the user taps the 😮 emoji more than 20 times in one minute. This action publishes a message to the `illuminate-upgrade-reaction` channel with the following payload:

```json
{
  "emoji": "${Reaction}", // in this case, ${Reaction} == 😮
  "replacementEmoji": "❤️"
}
```

:::note Value of the emoji key
The actual value of the `emoji` key is `${Reaction}`, but in this case, the update to the ❤️ emoji only happens when the user taps the 😮 emoji because of the condition in the [decision](#create-a-decision).
:::

This is a simple example, but it shows how non-technical staff can use Illuminate to change the behavior of the app without writing any code.

As opposed to the **Showcase: Live Event Upgrade Emoji to Default** action, Illuminate does publish the upgraded emoji to the `game.stream-reactions` channel in this case. Even though, it is still the responsibility of the client to display the upgraded emoji, you can use Illuminate to override the emoji in the app without modifying the client application.

#### Live event show dynamic ad

The **Showcase: Live Event Show Dynamic Ad** action displays an advert when the user taps the 😡 emoji in a show of frustration.

In the Live Events demo, this is triggered when the user taps the 😡 emoji more than 20 times in one minute. This action publishes a message to the `illuminate-show-ad` channel with the following payload:

```json
{
  "adId": 3, 
  "clickPoints": 12
}
```

| Field | Type | Description |
| --- | --- | --- |
| `adId` | Integer | Identifies which dynamic ad to display in the client UI. |
| `clickPoints` | Integer | The number of points awarded when the user clicks the ad providing a reward loop for interaction and encouraging engagement. |

Like with the emojis, Illuminate doesn't actually display the ad. It only notifies the client that the ad should be displayed by publishing a message and the client is responsible for displaying the ad accordingly. For more information, refer to [Listen for triggers and react](#listen-for-triggers-and-react).

:::note How the demo handles ads
Although these values (`3` and `12`) are hardcoded in the demo, they could be dynamic. For example, you could create a condition in the [decision](#create-a-decision) that the `adId` to show can change based on how many times the emoji is clicked.
:::

### Listen for triggers and react

Thus far, we've established that Illuminate consumes the data from your app and makes decisions based on the data. Now, let's see how the app reacts to the data that Illuminate sends.

:::note Live Events demo implementation
The demo is designed to be easy to set up and understand, so it uses hard-coded values and PubNub messaging for all communication between Illuminate and the client application.
In a production environment, you would typically have a server that sits between Illuminate and the client app, listening for either PubNub messages or webhooks from Illuminate, and dynamically adjusting the content to show or targeting specific users to receive the upgraded emoji.
:::

The application listens for real-time triggers from Illuminate by subscribing to the relevant PubNub channels. The Live Events demo handles messages on the `game.stream-reactions` and `illuminate-show-ad` channels and reacts to them in real-time.

When Illuminate triggers an emoji upgrade or ad, it can take various actions. In this demo, it publishes a message to the `game.stream-reactions` or `illuminate-show-ad` channels (we configured this in the [Create a decision](#create-a-decision) step), but it could also trigger webhooks, send emails, or perform any other custom action you define. Depending on which channel the message is published to, the app reacts differently.

The `StreamWidget` component subscribes to the `illuminate-upgrade-reaction` channel and calls the `upgradeEmoji` function when a message is received on that channel. It is in that method that the current emoji to upgraded emoji mapping is handled. However, if you remember the [Live Event Upgrade Emoji to Heart](#live-event-upgrade-emoji-to-heart) decision, Illuminate actually publishes the upgraded emoji to the `game.stream-reactions` channel when the user taps the 😮 emoji more than 20 times in one minute. In this case, the `emojiMap` is not used and the app displays the ❤️ emoji sent by Illuminate.

```javascript
//  Illuminate: Upgrade emoji
const illuminateEmojiChannel = chat.sdk.channel(illuminateUpgradeReaction)
const illuminateEmojiSubscription = illuminateEmojiChannel.subscription({
  receivePresenceEvents: false
})
illuminateEmojiSubscription.onMessage = messageEvent => {
  //  Received a request to upgrade a specific emoji
  const emojiToUpgrade = messageEvent.message.emoji
  const replacementEmoji = messageEvent.message.replacementEmoji
  upgradeEmoji(emojiToUpgrade, replacementEmoji)
}
illuminateEmojiSubscription.subscribe()
return () => {
  reactionsSubscription.unsubscribe()
  occupancySubscription.unsubscribe()
  illuminateEmojiSubscription.unsubscribe()
}

// other code

const emojiMap = {
    '👏': '🙌',
    '😢': '😭',
    '😡': '🤬',
    '😮': '🤯',
    '🔥': '😎',
    '🎉': '🥳'
  }

function upgradeEmoji (
    emoji: string,
    overrideDefaultEmoji: string | null = null
  ) {
    setReactions(prevReactions =>
      prevReactions.map(reaction =>
        reaction.emoji === emoji
          ? {
              ...reaction,
              emoji:
                overrideDefaultEmoji ||
                (emojiMap[reaction.emoji] ?? reaction.emoji), // Add fallback for undefined emojiMap value
              upgraded: true
            }
          : reaction
      )
    )
  }
```

Dynamic ads are managed by the `CommonMessageHandler` component. It keeps a `dynamicAd` state and listens to the `dynamicAdChannelId` channel. When a message is received, `CommonMessageHandler` processes it and calls `setDynamicAd`. If `setDynamicAd` is given an ad object, the `AdvertsOfferWidget` is shown. If `setDynamicAd` is called with null, the ad is removed from view.

In the Live Events demo, the `CommonMessageHandler` component is responsible for processing messages from Illuminate and managing the application state.

```typescript
export async function CommonMessageHandler(
  isGuidedDemo,
  messageEvent,
  onSetNotification,
  onSetDynamicAd
) {
    // push notifications code, irrelevant to this example
  } else if (messageEvent.channel === dynamicAdChannelId) {
    // Handle dynamic ads
    const adId = messageEvent.message.adId;
    const clickPoints = messageEvent.message.clickPoints;
    if (adId && clickPoints) {
      onSetDynamicAd({ adId: adId, clickPoints: clickPoints });
    } else {
      onSetDynamicAd(null);
    }
  } else {
    console.error("Unrecognized message channel");
  }
}
```

The actual display of the ad is handled by the `AdvertsOfferWidget` component, which looks up the ad image source from a constant array of ads. If the ad isn't found, it shows a placeholder image.

By leveraging PubNub Illuminate, you can automate real-time decisioning in your applications that respond instantly to engagement and sentiment. The best thing about it is that you don't need to change your app code to do it. Once set up in the app, you can change the decision rules and actions directly in Illuminate.

## Terms in this document

* **Action** - The type of activity (procedure) to execute when a condition is satisfied (for example, sending a message).
* **Business Object** - A container for data fields and metrics that defines aggregations and data sources.
* **Channel** - A pathway for sending and receiving messages between devices, created automatically when you first use it, that can handle any number of users and messages for different communication needs, like 1-1 text chats, group conversations, and other data streaming.
* **Channel pattern** - A way to group and analyze channel data to track performance metrics like message counts and user engagement over time with PubNub Insights.
* **Condition** - A requirement that must be satisfied or evaluated to true for an action to be executed. Input in a decision table.
* **Dashboard** - A collection of widgets (charts) that give an overview of the metrics one is evaluating.
* **Data fields** - Data you want Illuminate to track. These can be quantitative (measures), like "Number" or "Timestamp" or qualitative (dimensions) values, like "String" that can be used to categorize and segment data. Data fields can be aggregated and calculated.
* **Decision** - A collection (or decision table) of conditions and actions. When conditions are satisfied, the corresponding actions are triggered as per defined rules.
* **Message** - A unit of data transmitted between clients or between a client and a server in PubNub, containing information such as text, binary data, or structured data formats like JSON. Messages are sent over channels and can be tracked for delivery and read status.
* **Metric** - What exactly is evaluated using measures and dimensions (collectively called data fields), as well as aggregation functions.
* **Publish Key** - A unique identifier that allows your application to send messages to PubNub channels. It's part of your app's credentials and should be kept secure.
* **Rule** - A definition (row in a decision table) stating which action should be triggered for which condition.
* **Subscribe Key** - A unique identifier that allows your application to receive messages from PubNub channels. It's part of your app's credentials and should be kept secure.
* **User** - An individual or entity that interacts with a system, application, or service. In PubNub, a user typically refers to someone who sends or receives messages through the platform, identified by a unique user ID or username.
* **User ID** - UTF-8 encoded, unique string of up to 92 characters used to identify a single client (end user, device, or server) that connects to PubNub.
