---
source_url: https://www.pubnub.com/docs/sdks/javascript
title: JavaScript API & SDK Docs 11.0.1
updated_at: 2026-05-19T12:12:40.756Z
sdk_name: PubNub JavaScript SDK
sdk_version: 11.0.1
---

> 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


# JavaScript API & SDK Docs 11.0.1

PubNub JavaScript SDK, use the latest version: 11.0.1

Install:

```bash
npm install pubnub@11.0.1
```

:::note Chat SDK
If you want to create a chat app, you can use our [Chat SDK](https://www.pubnub.com/docs/chat/chat-sdk), which relies on the JavaScript SDK, is written in TypeScript, and offers a set of chat-specific methods to manage users, channels, messages, typing indicators, quotes, mentions, threads, and many more.
:::

This guide walks you through a simple "Hello, World" application that demonstrates the core concepts of PubNub:

* Setting up a connection
* Sending messages
* Receiving messages in real-time

## Overview

This guide helps you get up and running with PubNub in your JavaScript application. The JavaScript software development kit (SDK) provides a simple interface for integrating PubNub real-time messaging. Since JavaScript is commonly used across different platforms, we provide platform-specific guidance for:

* **Web**: For developers building browser-based applications
* **Node.js**: For server-side applications
* **React**: For browser-based React applications using hooks and components
* **React Native**: For mobile app development

The core PubNub concepts and API usage remain the same across all platforms, but implementation details like lifecycle management and UI updates differ. Select the appropriate tab in each section to see platform-specific guidance.

You can use either JavaScript or TypeScript with any of these platforms. The only difference is in how you import PubNub:

* For JavaScript files (`.js` extension): `const PubNub = require('pubnub');`
* For TypeScript files (`.ts` extension): `import PubNub from 'pubnub';`

JavaScript SDK supports a wide variety of environments including browsers, Node.js, React Native, React, Angular, Vue, and other JavaScript frameworks.

## Prerequisites

Before we dive in, make sure you have:

* A basic understanding of JavaScript
* For browser applications: A modern web browser
* For Node.js: Node.js installed (version 18 or later)
* For React: Node.js installed (version 18 or later) and a React project (e.g. created with [Vite](https://vitejs.dev/))
* For React Native: React Native development environment set up
* A PubNub account (we'll help you set this up!)
* (Optional) If you want to use TypeScript: TypeScript installed (version 4.0 or later)

:::tip JavaScript environment setup
For detailed guidance on Node.js versions, package managers (npm, yarn, pnpm, bun), TypeScript configuration, and modern build tools like Vite, refer to the [JavaScript Environment Setup](https://www.pubnub.com/docs/sdks/javascript/environment-setup) guide.
:::

## Setup

### Get your PubNub keys

First, get your PubNub keys:

* [Sign in](https://admin.pubnub.com/#/login) or [create an account](https://admin.pubnub.com/#/signup) on the PubNub Admin Portal
* Create an app (or use an existing one)
* Find your publish and subscribe keys in the app dashboard

When you create an app, PubNub automatically generates a keyset. You can use the same keyset for development and production, but we recommend separate keysets for each environment to improve security and management.

### Install the SDK

:::note SDK version
Always use the latest SDK version to have access to the newest features and avoid security vulnerabilities, bugs, and performance issues.
:::

###### Web

To integrate PubNub into your web project, add the JavaScript SDK to your HTML page using the CDN:

```html
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.11.0.1.js"></script>
```

You can also use the minified version for production:

```html
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.11.0.1.min.js"></script>
```

###### Node.js

To integrate PubNub into your Node.js project, install the SDK using npm:

```bash
npm install pubnub
```

Then import it in your project:

```javascript
const PubNub = require('pubnub');
```

###### React Native

For React Native projects, install the PubNub SDK:

```bash
npm install pubnub
```

Then import it in your project:

```javascript
import PubNub from 'pubnub';
```

###### Source code

Clone the [GitHub repository](https://github.com/pubnub/javascript):

```bash
git clone https://github.com/pubnub/javascript
```

###### React

Install the PubNub SDK using npm (or yarn/pnpm) in your React project:

```bash
npm install pubnub
```

Then import it in your component or app entry point:

```jsx
import PubNub from 'pubnub';
```

If you don't have a React project yet, create one with [Vite](https://vitejs.dev/):

```bash
npm create vite@latest my-pubnub-app -- --template react
cd my-pubnub-app
npm install
npm install pubnub
```

## Steps

### Initialize PubNub

#### Web

Create an instance of the PubNub class with your keys and a unique user ID:

```javascript
const pubnub = new PubNub({
    publishKey: "demo",
    subscribeKey: "demo",
    userId: "web-user-" + Math.floor(Math.random() * 1000)
});
```

Make sure to replace the demo keys with your app's publish and subscribe keys from the Admin Portal.

#### Node.js

Create an instance of the PubNub class with your keys and a unique user ID:

```javascript
const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});
```

#### React Native

Create an instance of the PubNub class with your keys and a unique user ID:

```javascript
const pubnub = new PubNub({
    publishKey: "demo",
    subscribeKey: "demo",
    userId: "rn-user-" + Math.floor(Math.random() * 1000)
});
```

In a real React Native application, you would typically initialize PubNub inside a component using hooks for proper lifecycle management:

```javascript
// Example of initialization in a React component (optional)
useEffect(() => {
    // Clean up on component unmount
    return () => {
        if (pubnub) {
            pubnub.removeAllListeners();
            pubnub.destroy();
        }
    };
}, [pubnub]);
```

#### React

In React, use `useRef` to hold the PubNub instance so it's stable across re-renders, and initialize it inside a `useEffect` hook. Always clean up in the effect's return function to avoid memory leaks.

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

function App() {
  const pubnubRef = useRef(null);

  useEffect(() => {
    pubnubRef.current = new PubNub({
      publishKey: 'YOUR_PUBLISH_KEY',
      subscribeKey: 'YOUR_SUBSCRIBE_KEY',
      userId: 'react-user-' + Math.floor(Math.random() * 1000),
    });

    return () => {
      if (pubnubRef.current) {
        pubnubRef.current.removeAllListeners();
        pubnubRef.current.destroy();
      }
    };
  }, []);

  return <div>Your React app</div>;
}
```

Make sure to replace the placeholder keys with your app's publish and subscribe keys from the Admin Portal.

For more information, refer to the [Configuration](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration) section of the SDK documentation.

### Set up event listeners

Listeners help the application react to events and messages. You can implement custom app logic to respond to each type of message or event.

For complete details on subscribing and handling events, refer to the [Publish and Subscribe API Reference](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe).

#### Web

```javascript
// Add listener to handle messages, presence events, and connection status
pubnub.addListener({
    message: function(event) {
        // Handle message event
        console.log("New message:", event.message);
        // Display message in the UI
        displayMessage(event.message);
    },
    presence: function(event) {
        // Handle presence event
        console.log("Presence event:", event);
        console.log("Action:", event.action); // join, leave, timeout
        console.log("Channel:", event.channel);
        console.log("Occupancy:", event.occupancy);
    },
    status: function(event) {
        // Handle status event
        console.log("Status event:", event);
        if (event.category === "PNConnectedCategory") {
            console.log("Connected to PubNub channels!");
        } else if (event.category === "PNNetworkIssuesCategory") {
            console.log("Connection lost. Attempting to reconnect...");
        }
    }
});

// Function to display messages in the UI
function displayMessage(message) {
    const messagesDiv = document.getElementById('messages');
    const messageElement = document.createElement('div');
    messageElement.className = 'message';
    
    // Format message based on content
    let content = '';
    if (typeof message === 'object' && message.text) {
        content = `${message.sender || 'User'}: ${message.text}`;
    } else {
        content = JSON.stringify(message);
    }
    
    messageElement.textContent = content;
    messagesDiv.appendChild(messageElement);
    messagesDiv.scrollTop = messagesDiv.scrollHeight; // Auto-scroll to bottom
}
```

#### Node.js

```javascript
// Add listener to handle messages, presence events, and connection status
pubnub.addListener({
  message: function (event: Subscription.Message) {
    // Handle message event
    console.log('New message:', event.message);
    // Format and display received message
    const displayText = (() => {
      if (typeof event.message === 'object' && event.message && 'text' in event.message) {
        const messageObj = event.message as { text?: string; sender?: string };
        return `${messageObj.sender || 'User'}: ${messageObj.text}`;
      } else {
        return `Message: ${JSON.stringify(event.message)}`;
      }
    })();
    console.log(displayText);
  },
  presence: function (event: Subscription.Presence) {
    // Handle presence event
    console.log('Presence event:', event);
    console.log('Action:', event.action); // join, leave, timeout
    console.log('Channel:', event.channel);
  },
  status: function (event) {
    // Handle status event
    if (event.category === 'PNConnectedCategory') {
      console.log('Connected to PubNub chat!');
      console.log('Your user ID is:', pubnub.userId);
    } else if (event.category === 'PNNetworkIssuesCategory') {
      // if eventEngine is not enabled, this event will be triggered when subscription encounter network issues.
      console.log('Connection lost');
      // handle reconnection
    } else if (event.category === 'PNDisconnectedUnexpectedlyCategory') {
      // If enableEventEngine: true set in the constructor, this event will be triggered when the connection is lost.
      console.log('Disconnected unexpectedly.');
    }
  },
});
```

#### React Native

```jsx
// App.js or App.tsx for TypeScript projects

// Imports
import React, { useState, useEffect, useRef } from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  TextInput,
  TouchableOpacity,
  FlatList,
  KeyboardAvoidingView,
  Platform,
  StatusBar,
  ActivityIndicator,
  Alert
} from 'react-native';
import PubNub from 'pubnub';

// TypeScript interfaces (for TypeScript projects)
// For JavaScript, you can remove this section
interface ChatMessage {
  text: string;
  sender?: string;
  time?: string;
}

interface MessageItem {
  id: string;
  message: ChatMessage;
}

// Main App Component
export default function App() {
  // State variables
  const [pubnub, setPubnub] = useState(null);
  const [messages, setMessages] = useState([]);
  const [inputText, setInputText] = useState('');
  const [isConnected, setIsConnected] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  
  // Reference to the FlatList for auto-scrolling
  const flatListRef = useRef(null);

  // Initialize PubNub on component mount
  useEffect(() => {
    // Create a new PubNub instance
    const pubnubInstance = new PubNub({
      publishKey: "demo",
      subscribeKey: "demo",
      userId: "rn-user-" + Math.floor(Math.random() * 1000)
    });
    
    // Add listener to handle events
    pubnubInstance.addListener({
      // Message handler - called when a message is received
      message: function(event) {
        setMessages(messages => [
          ...messages, 
          { 
            id: event.timetoken || Date.now().toString(),
            message: event.message
          }
        ]);
        
        // Auto-scroll to bottom when new messages arrive
        setTimeout(() => {
          if (flatListRef.current && messages.length > 0) {
            flatListRef.current.scrollToEnd({ animated: true });
          }
        }, 100);
      },
      
      // Presence handler - called for join/leave events
      presence: function(event) {
        console.log("Presence event:", event);
        if (event.action === 'join') {
          // Someone joined the channel
          Alert.alert("User Joined", `${event.uuid} joined the chat`);
        } else if (event.action === 'leave' || event.action === 'timeout') {
          // Someone left the channel
          Alert.alert("User Left", `${event.uuid} left the chat`);
        }
      },
      
      // Status handler - called for connection status changes
      status: function(event) {
        console.log("Status event:", event);
        if (event.category === "PNConnectedCategory") {
          setIsConnected(true);
          setIsLoading(false);
          console.log("Connected to PubNub!");
        } else if (event.category === "PNNetworkIssuesCategory") {
          setIsConnected(false);
          console.log("Connection lost. Attempting to reconnect...");
        } else if (event.category === "PNReconnectedCategory") {
          setIsConnected(true);
          console.log("Reconnected to PubNub!");
        }
      }
    });
    
    // Create a channel entity and subscription
    const channel = pubnubInstance.channel('hello_world');
    const subscription = channel.subscription({
      receivePresenceEvents: true
    });
    
    // Subscribe to the channel
    subscription.subscribe();
    
    // Update state with PubNub instance
    setPubnub(pubnubInstance);
    
    // Clean up on component unmount
    return () => {
      pubnubInstance.removeAllListeners();
      pubnubInstance.destroy();
      console.log("Cleaned up PubNub connection");
    };
  }, []); // Empty dependency array ensures this runs only once on mount

  // Function to publish a message
  const publishMessage = async () => {
    // Don't send empty messages or if not connected
    if (!inputText.trim() || !pubnub || !isConnected) return;
    
    try {
      // Create message object
      const messageObject: ChatMessage = {
        text: inputText,
        sender: pubnub.getUUID(),
        time: new Date().toISOString()
      };
      
      // Publish to PubNub
      const result = await pubnub.publish({
        message: messageObject,
        channel: 'hello_world'
      });
      
      console.log("Message published with timetoken:", result.timetoken);
      
      // Clear input after successful send
      setInputText('');
    } catch (error) {
      console.error("Publish failed:", error);
      Alert.alert(
        "Message Failed", 
        "Could not send your message. Please try again."
      );
    }
  };

  // Render a message item for the FlatList
  const renderMessageItem = ({ item }) => {
    const isCurrentUser = item.message.sender === pubnub?.getUUID();
    const messageTime = item.message.time 
      ? new Date(item.message.time).toLocaleTimeString([], { 
          hour: '2-digit', 
          minute: '2-digit' 
        }) 
      : '';
      
    return (
      <View style={[
        styles.messageContainer,
        isCurrentUser ? styles.sentMessage : styles.receivedMessage
      ]}>
        <Text style={styles.senderText}>
          {isCurrentUser ? 'You' : (item.message.sender || 'User')}
        </Text>
        <Text style={styles.messageText}>{item.message.text}</Text>
        <Text style={styles.timeText}>{messageTime}</Text>
      </View>
    );
  };

  // Main component render
  return (
    <SafeAreaView style={styles.safeArea}>
      <StatusBar barStyle="dark-content" />
      
      {isLoading ? (
        // Loading screen
        <View style={styles.loadingContainer}>
          <ActivityIndicator size="large" color="#4b0082" />
          <Text style={styles.loadingText}>Connecting to PubNub...</Text>
        </View>
      ) : (
        // Chat UI
        <KeyboardAvoidingView
          behavior={Platform.OS === "ios" ? "padding" : "height"}
          style={styles.container}
          keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}
        >
          {/* Header */}
          <View style={styles.header}>
            <Text style={styles.headerText}>PubNub Chat</Text>
            <View style={[
              styles.connectionIndicator,
              isConnected ? styles.connected : styles.disconnected
            ]} />
          </View>
          
          {/* Messages List */}
          <FlatList
            ref={flatListRef}
            data={messages}
            renderItem={renderMessageItem}
            keyExtractor={(item) => item.id}
            style={styles.messagesList}
            contentContainerStyle={styles.messagesContent}
            onContentSizeChange={() => 
              flatListRef.current?.scrollToEnd({ animated: false })
            }
          />
          
          {/* Input Area */}
          <View style={styles.inputContainer}>
            <TextInput
              style={styles.input}
              value={inputText}
              onChangeText={setInputText}
              placeholder="Type a message..."
              placeholderTextColor="#aaa"
              returnKeyType="send"
              onSubmitEditing={publishMessage}
            />
            <TouchableOpacity
              style={[
                styles.sendButton,
                (!inputText.trim() || !isConnected) && styles.sendButtonDisabled
              ]}
              onPress={publishMessage}
              disabled={!inputText.trim() || !isConnected}
            >
              <Text style={styles.sendButtonText}>Send</Text>
            </TouchableOpacity>
          </View>
        </KeyboardAvoidingView>
      )}
    </SafeAreaView>
  );
}

// Component styles
const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  container: {
    flex: 1,
  },
  loadingContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#555',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  headerText: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
  },
  connectionIndicator: {
    width: 12,
    height: 12,
    borderRadius: 6,
  },
  connected: {
    backgroundColor: '#4CAF50',
  },
  disconnected: {
    backgroundColor: '#F44336',
  },
  messagesList: {
    flex: 1,
    padding: 8,
  },
  messagesContent: {
    paddingBottom: 8,
  },
  messageContainer: {
    padding: 12,
    borderRadius: 16,
    marginVertical: 4,
    maxWidth: '80%',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 1,
    elevation: 1,
  },
  sentMessage: {
    alignSelf: 'flex-end',
    backgroundColor: '#DCF8C6',
    borderBottomRightRadius: 4,
  },
  receivedMessage: {
    alignSelf: 'flex-start',
    backgroundColor: '#fff',
    borderBottomLeftRadius: 4,
  },
  senderText: {
    fontWeight: 'bold',
    fontSize: 13,
    marginBottom: 4,
    color: '#333',
  },
  messageText: {
    fontSize: 15,
    color: '#333',
  },
  timeText: {
    fontSize: 11,
    color: '#999',
    alignSelf: 'flex-end',
    marginTop: 4,
  },
  inputContainer: {
    flexDirection: 'row',
    padding: 12,
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  input: {
    flex: 1,
    height: 40,
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 20,
    paddingHorizontal: 16,
    marginRight: 8,
    backgroundColor: '#fff',
    color: '#333',
  },
  sendButton: {
    height: 40,
    paddingHorizontal: 16,
    borderRadius: 20,
    backgroundColor: '#4b0082',
    justifyContent: 'center',
    alignItems: 'center',
  },
  sendButtonDisabled: {
    backgroundColor: '#B39DDB',
  },
  sendButtonText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});
```

To use this example in your React Native project:

1. Create a new React Native project: # Using Expo (easiest for beginners)npx create-expo-app PubNubChatAppcd PubNubChatApp # Or using React Native CLInpx react-native init PubNubChatAppcd PubNubChatApp
2. Install the PubNub SDK: npm install pubnub
3. Replace the content of App.js (or App.tsx for TypeScript) with the code above.
4. Run your app: # For Exponpx expo start # For React Native CLInpx react-native run-ios# ornpx react-native run-android

The example includes:

* PubNub initialization with proper cleanup
* Real-time message sending and receiving
* Messages display in a scrollable chat UI
* Connection status indicator
* Presence notifications (when users join/leave)
* Auto-scrolling message list
* Proper keyboard handling
* Error handling for failed messages
* Loading state while connecting
* Full styling for a production-ready appearance

#### React

```jsx
import React, { useState, useRef, useEffect } from 'react';
import PubNub from 'pubnub';

function App() {
  const pubnubRef = useRef(null);
  const [messages, setMessages] = useState([]);
  const [onlineCount, setOnlineCount] = useState(0);
  const [isConnected, setIsConnected] = useState(false);

  useEffect(() => {
    pubnubRef.current = new PubNub({
      publishKey: 'YOUR_PUBLISH_KEY',
      subscribeKey: 'YOUR_SUBSCRIBE_KEY',
      userId: 'react-user-' + Math.floor(Math.random() * 1000),
    });

    pubnubRef.current.addListener({
      message: (event) => {
        setMessages((prev) => [...prev, event.message]);
      },
      presence: (event) => {
        // event.action: 'join' | 'leave' | 'timeout' | 'interval' | 'state-change'
        // occupancy is present on join/leave/timeout/interval but not on state-change
        if (event.action !== 'state-change') setOnlineCount(event.occupancy);
      },
      status: (event) => {
        if (event.category === 'PNConnectedCategory') {
          setIsConnected(true);
        } else if (event.category === 'PNNetworkIssuesCategory') {
          setIsConnected(false);
        }
      },
    });

    const channel = pubnubRef.current.channel('hello_world');
    const subscription = channel.subscription({ receivePresenceEvents: true });
    subscription.subscribe();

    return () => {
      subscription.unsubscribe();
      pubnubRef.current.removeAllListeners();
      pubnubRef.current.destroy();
    };
  }, []);

  return (
    <div>
      <p>{isConnected ? `Connected — ${onlineCount} online` : 'Connecting...'}</p>
      <ul>
        {messages.map((msg, i) => (
          <li key={i}>{typeof msg === 'object' ? JSON.stringify(msg) : msg}</li>
        ))}
      </ul>
    </div>
  );
}
```

### Create a subscription

To receive messages on a channel, you need to subscribe to it. PubNub offers an entity-based subscription approach which provides more control and flexibility:

#### Web

```javascript
// Create a channel entity
const channel = pubnub.channel('hello_world');

// Create a subscription for this channel
const subscription = channel.subscription();

// Subscribe
subscription.subscribe();
```

#### Node.js

```javascript
// Create a channel entity
const channel = pubnub.channel('hello_world');

// Create a subscription
const subscription = channel.subscription({
  receivePresenceEvents: true, // to receive presence events
});

// Subscribe
subscription.subscribe();
```

#### React Native

In React Native, we typically subscribe within a useEffect hook:

```javascript
useEffect(() => {
    if (!pubnub) return;
    
    // Create a channel entity
    const channel = pubnub.channel('hello_world');
    
    // Create a subscription
    const subscription = channel.subscription({
        receivePresenceEvents: true
    });
    
    // Subscribe
    subscription.subscribe();
    
    // Clean up on unmount
    return () => {
        // First remove listeners to prevent callbacks during cleanup
        pubnub.removeAllListeners();
        
        // Then unsubscribe if needed
        if (subscription) {
            subscription.unsubscribe();
        }
        
        // Note: Only call destroy() if this component owns the pubnub instance
        // If the pubnub instance is shared, consider only removing listeners
    };
}, [pubnub]);
```

#### React

In React, create the subscription inside a `useEffect` hook. The cleanup function ensures PubNub unsubscribes when the component unmounts.

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

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

function App() {
  useEffect(() => {
    const channel = pubnub.channel('hello_world');
    const subscription = channel.subscription({
      receivePresenceEvents: true,
    });
    subscription.subscribe();

    return () => {
      subscription.unsubscribe();
      pubnub.removeAllListeners();
    };
  }, []);

  return <div>Subscribed to hello_world</div>;
}
```

For more information, refer to the [Subscribe](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe) section of the SDK documentation.

### Publish messages

Once you've set up your subscription, you can start publishing messages to channels.

When you publish a message to a channel, PubNub delivers that message to everyone who is subscribed to that channel.

A message can be any type of JavaScript Object Notation (JSON)-serializable data (such as objects, arrays, integers, strings) that is smaller than 32 KiB.

#### Web

```javascript
// Function to publish a message
async function publishMessage(text) {
    if (!text.trim()) return;
    
    try {
        const result = await pubnub.publish({
            message: {
                text: text,
                sender: pubnub.getUUID(),
                time: new Date().toISOString()
            },
            channel: 'hello_world'
        });
        console.log("Message published with timetoken:", result.timetoken);
    } catch (error) {
        console.error("Publish failed:", error);
    }
}

// Example: Call this function when a button is clicked
document.getElementById('send-button').addEventListener('click', function() {
    const input = document.getElementById('message-input');
    publishMessage(input.value);
    input.value = '';
});
```

#### Node.js

```javascript
// Function to publish a message
async function publishMessage(text: string) {
  if (!text.trim()) return;

  try {
    const result = await pubnub.publish({
      message: {
        text: text,
        sender: pubnub.userId,
        time: new Date().toISOString(),
      },
      channel: 'hello_world',
    });
    console.log(`Message published with timetoken: ${result.timetoken}`);
    console.log(`You: ${text}`);
  } catch (error) {
    console.error(
      `Publish failed: ${error}.${
        (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
      }`,
    );
  }
}

// Example: publish a message
const text_message = 'Hello, world!';
publishMessage(text_message);
```

#### React Native

```javascript
// State for the input text
const [inputText, setInputText] = useState('');

// Function to publish a message
const publishMessage = async () => {
    if (!inputText.trim() || !pubnub) return;
    
    try {
        const result = await pubnub.publish({
            message: {
                text: inputText,
                sender: pubnub.getUUID(),
                time: new Date().toISOString()
            },
            channel: 'hello_world'
        });
        console.log("Message published with timetoken:", result.timetoken);
        setInputText(''); // Clear input after sending
    } catch (error) {
        console.error("Publish failed:", error);
        Alert.alert("Error", "Failed to send message");
    }
};

// In your render function
return (
    <View style={styles.container}>
        <TextInput
            value={inputText}
            onChangeText={setInputText}
            placeholder="Type a message..."
            style={styles.input}
        />
        <Button title="Send" onPress={publishMessage} />
    </View>
);
```

#### React

```jsx
import React, { useState } from 'react';

function MessageInput({ pubnub }) {
  const [inputText, setInputText] = useState('');

  const publishMessage = async () => {
    if (!inputText.trim() || !pubnub) return;

    try {
      const result = await pubnub.publish({
        message: {
          text: inputText,
          sender: pubnub.userId,
          time: new Date().toISOString(),
        },
        channel: 'hello_world',
      });
      console.log('Message published with timetoken:', result.timetoken);
      setInputText('');
    } catch (error) {
      console.error('Publish failed:', error);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={inputText}
        onChange={(e) => setInputText(e.target.value)}
        onKeyDown={(e) => e.key === 'Enter' && publishMessage()}
        placeholder="Type a message..."
      />
      <button onClick={publishMessage}>Send</button>
    </div>
  );
}
```

### Run the app

Once you've implemented all the previous steps (initialization, listeners, subscription, and publishing), you're ready to run your application:

#### Web

1. Save your HTML file with all the JavaScript code.
2. Open the file in a web browser.
3. Type a message in the input box and click **Send**.
4. You should see your message appear in the messages area.
5. To see real-time communication, open the same file in another browser tab.

#### Node.js

1. Save your JavaScript file (e.g., index.js).
2. Run the file using Node.js: node index.js
3. Type messages in the console and press Enter to send.
4. To see real-time communication, open another terminal window and run another instance of your app.

#### React Native

1. Start your React Native app: npm run android# ornpm run ios# ornpm run web
2. The app should launch on the selected platform.
3. Type a message in the input field and tap Send.
4. You should see your message appear in the messages list.
5. To see real-time communication, run the app on another device or simulator.

#### React

1. Start your Vite-based React app: npm run dev
2. Open http://localhost:5173 in your browser.
3. Type a message in the input field and click Send.
4. You should see your message appear in the messages list.
5. To see real-time communication, open the same URL in another browser tab.

## Complete example

### Web

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>PubNub Chat Example</title>
    <script src="https://cdn.pubnub.com/sdk/javascript/pubnub.11.0.1.js"></script>
    <style>
        #chat-container {
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
            font-family: Arial, sans-serif;
        }
        #messages {
            height: 300px;
            overflow-y: auto;
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
            background-color: #f9f9f9;
        }
        .message {
            margin-bottom: 8px;
            padding: 8px;
            border-radius: 4px;
            background-color: #e9e9e9;
        }
        .input-container {
            display: flex;
        }
        #message-input {
            flex-grow: 1;
            padding: 8px;
            margin-right: 10px;
        }
    </style>
</head>
<body>
    <div id="chat-container">
        <h1>PubNub Chat</h1>
        <div id="messages"></div>
        <div class="input-container">
            <input type="text" id="message-input" placeholder="Type a message..." />
            <button id="send-button">Send</button>
        </div>
    </div>

    <script>
        // Initialize PubNub
        const pubnub = new PubNub({
            publishKey: "demo",
            subscribeKey: "demo",
            userId: "web-user-" + Math.floor(Math.random() * 1000)
        });

        // Display messages in the UI
        function displayMessage(message) {
            const messagesDiv = document.getElementById('messages');
            const messageElement = document.createElement('div');
            messageElement.className = 'message';
            
            // Format message based on content
            let content = '';
            if (typeof message === 'object' && message.text) {
                content = `${message.sender || 'User'}: ${message.text}`;
            } else {
                content = JSON.stringify(message);
            }
            
            messageElement.textContent = content;
            messagesDiv.appendChild(messageElement);
            messagesDiv.scrollTop = messagesDiv.scrollHeight; // Auto-scroll to bottom
        }

        // Add listener to handle messages
        pubnub.addListener({
            message: function(event) {
                displayMessage(event.message);
            },
            status: function(event) {
                if (event.category === "PNConnectedCategory") {
                    console.log("Connected to PubNub!");
                    // Display a connection message
                    const messagesDiv = document.getElementById('messages');
                    const statusElement = document.createElement('div');
                    statusElement.textContent = "Connected to chat!";
                    statusElement.style.textAlign = "center";
                    statusElement.style.color = "green";
                    messagesDiv.appendChild(statusElement);
                }
            }
        });

        // Subscribe to a channel
        const channel = pubnub.channel('hello_world');
        const subscription = channel.subscription();
        subscription.subscribe();

        // Publish message function
        async function publishMessage(text) {
            if (!text.trim()) return;
            
            try {
                const result = await pubnub.publish({
                    message: {
                        text: text,
                        sender: pubnub.getUUID(),
                        time: new Date().toISOString()
                    },
                    channel: 'hello_world'
                });
                console.log("Message published with timetoken:", result.timetoken);
            } catch (error) {
                console.error("Publish failed:", error);
            }
        }

        // Add event listeners for the UI
        document.getElementById('send-button').addEventListener('click', function() {
            const input = document.getElementById('message-input');
            publishMessage(input.value);
            input.value = '';
        });

        document.getElementById('message-input').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                const input = document.getElementById('message-input');
                publishMessage(input.value);
                input.value = '';
            }
        });
    </script>
</body>
</html>
```

### Node.js

```javascript
// Save this file as index.js/.ts

// 1. Import pubnub
// import PubNub from 'pubnub';

// 2. Initialize PubNub with demo keys and a random user ID
const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

// 3. Add listener to handle messages, presence events, and connection status
pubnub.addListener({
  // Handle incoming messages
  message: function (event) {
    // Handle message event
    console.log('New message:', event.message);
    // Format and display received message
    const displayText = (() => {
      if (typeof event.message === 'object' && event.message && 'text' in event.message) {
        const messageObj = event.message as { text?: string; sender?: string };
        return `${messageObj.sender || 'User'}: ${messageObj.text}`;
      } else {
        return `Message: ${JSON.stringify(event.message)}`;
      }
    })();
    console.log(displayText);
  },

  // Handle presence events (join, leave, timeout)
  presence: function (event) {
    // Handle presence event
    console.log('Presence event:', event);
    console.log('Action:', event.action); // join, leave, timeout
    console.log('Channel:', event.channel);
  },

  // Handle connection status events
  status: function (event) {
    // Handle status event
    if (event.category === 'PNConnectedCategory') {
      console.log('Connected to PubNub chat!');
      console.log('Your user ID is:', pubnub.userId);
    } else if (event.category === 'PNNetworkIssuesCategory') {
      // if eventEngine is not enabled, this event will be triggered when subscription encounter network issues.
      console.log('Connection lost');
      // handle reconnection
    } else if (event.category === 'PNDisconnectedUnexpectedlyCategory') {
      // If enableEventEngine: true set in the constructor, this event will be triggered when the connection is lost.
      console.log('Disconnected unexpectedly.');
    }
  },
});

// 4. Create a channel entity and subscription with presence
const channel = pubnub.channel('hello_world');
const subscription = channel.subscription({
  receivePresenceEvents: true, // to receive presence events
});

// 5. Subscribe to the channel
subscription.subscribe();

// 6. Function to publish messages
async function publishMessage(text: string) {
  if (!text.trim()) return;

  try {
    // Create a message object with text, timestamp, and sender ID
    const message = {
      text: text,
      time: new Date().toISOString(),
      sender: pubnub.userId,
    };

    // Publish the message to the channel
    const response = await pubnub.publish({
      message: message,
      channel: 'hello_world',
      storeInHistory: true, // Save this message in history
    });

    // Success message (timetoken is the unique ID for this message)
    console.log(`\n✅ Message sent successfully!`);
  } catch (error) {
    // Handle publish errors
    console.error(
      `\n❌ Failed to send message: ${error}.${
        (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
      }`,
    );
  }
}

// 7. define the message and Publish that message.
const text_message = 'Hello, world!';
publishMessage(text_message);
```

### React Native

```jsx
// App.js or App.tsx for TypeScript projects

// Imports
import React, { useState, useEffect, useRef } from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  TextInput,
  TouchableOpacity,
  FlatList,
  KeyboardAvoidingView,
  Platform,
  StatusBar,
  ActivityIndicator,
  Alert
} from 'react-native';
import PubNub from 'pubnub';

// TypeScript interfaces (for TypeScript projects)
// For JavaScript, you can remove this section
interface ChatMessage {
  text: string;
  sender?: string;
  time?: string;
}

interface MessageItem {
  id: string;
  message: ChatMessage;
}

// Main App Component
export default function App() {
  // State variables
  const [pubnub, setPubnub] = useState(null);
  const [messages, setMessages] = useState([]);
  const [inputText, setInputText] = useState('');
  const [isConnected, setIsConnected] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  
  // Reference to the FlatList for auto-scrolling
  const flatListRef = useRef(null);

  // Initialize PubNub on component mount
  useEffect(() => {
    // Create a new PubNub instance
    const pubnubInstance = new PubNub({
      publishKey: "demo",
      subscribeKey: "demo",
      userId: "rn-user-" + Math.floor(Math.random() * 1000)
    });
    
    // Add listener to handle events
    pubnubInstance.addListener({
      // Message handler - called when a message is received
      message: function(event) {
        setMessages(messages => [
          ...messages, 
          { 
            id: event.timetoken || Date.now().toString(),
            message: event.message
          }
        ]);
        
        // Auto-scroll to bottom when new messages arrive
        setTimeout(() => {
          if (flatListRef.current && messages.length > 0) {
            flatListRef.current.scrollToEnd({ animated: true });
          }
        }, 100);
      },
      
      // Presence handler - called for join/leave events
      presence: function(event) {
        console.log("Presence event:", event);
        if (event.action === 'join') {
          // Someone joined the channel
          Alert.alert("User Joined", `${event.uuid} joined the chat`);
        } else if (event.action === 'leave' || event.action === 'timeout') {
          // Someone left the channel
          Alert.alert("User Left", `${event.uuid} left the chat`);
        }
      },
      
      // Status handler - called for connection status changes
      status: function(event) {
        console.log("Status event:", event);
        if (event.category === "PNConnectedCategory") {
          setIsConnected(true);
          setIsLoading(false);
          console.log("Connected to PubNub!");
        } else if (event.category === "PNNetworkIssuesCategory") {
          setIsConnected(false);
          console.log("Connection lost. Attempting to reconnect...");
        } else if (event.category === "PNReconnectedCategory") {
          setIsConnected(true);
          console.log("Reconnected to PubNub!");
        }
      }
    });
    
    // Create a channel entity and subscription
    const channel = pubnubInstance.channel('hello_world');
    const subscription = channel.subscription({
      receivePresenceEvents: true
    });
    
    // Subscribe to the channel
    subscription.subscribe();
    
    // Update state with PubNub instance
    setPubnub(pubnubInstance);
    
    // Clean up on component unmount
    return () => {
      pubnubInstance.removeAllListeners();
      pubnubInstance.destroy();
      console.log("Cleaned up PubNub connection");
    };
  }, []); // Empty dependency array ensures this runs only once on mount

  // Function to publish a message
  const publishMessage = async () => {
    // Don't send empty messages or if not connected
    if (!inputText.trim() || !pubnub || !isConnected) return;
    
    try {
      // Create message object
      const messageObject: ChatMessage = {
        text: inputText,
        sender: pubnub.getUUID(),
        time: new Date().toISOString()
      };
      
      // Publish to PubNub
      const result = await pubnub.publish({
        message: messageObject,
        channel: 'hello_world'
      });
      
      console.log("Message published with timetoken:", result.timetoken);
      
      // Clear input after successful send
      setInputText('');
    } catch (error) {
      console.error("Publish failed:", error);
      Alert.alert(
        "Message Failed", 
        "Could not send your message. Please try again."
      );
    }
  };

  // Render a message item for the FlatList
  const renderMessageItem = ({ item }) => {
    const isCurrentUser = item.message.sender === pubnub?.getUUID();
    const messageTime = item.message.time 
      ? new Date(item.message.time).toLocaleTimeString([], { 
          hour: '2-digit', 
          minute: '2-digit' 
        }) 
      : '';
      
    return (
      <View style={[
        styles.messageContainer,
        isCurrentUser ? styles.sentMessage : styles.receivedMessage
      ]}>
        <Text style={styles.senderText}>
          {isCurrentUser ? 'You' : (item.message.sender || 'User')}
        </Text>
        <Text style={styles.messageText}>{item.message.text}</Text>
        <Text style={styles.timeText}>{messageTime}</Text>
      </View>
    );
  };

  // Main component render
  return (
    <SafeAreaView style={styles.safeArea}>
      <StatusBar barStyle="dark-content" />
      
      {isLoading ? (
        // Loading screen
        <View style={styles.loadingContainer}>
          <ActivityIndicator size="large" color="#4b0082" />
          <Text style={styles.loadingText}>Connecting to PubNub...</Text>
        </View>
      ) : (
        // Chat UI
        <KeyboardAvoidingView
          behavior={Platform.OS === "ios" ? "padding" : "height"}
          style={styles.container}
          keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}
        >
          {/* Header */}
          <View style={styles.header}>
            <Text style={styles.headerText}>PubNub Chat</Text>
            <View style={[
              styles.connectionIndicator,
              isConnected ? styles.connected : styles.disconnected
            ]} />
          </View>
          
          {/* Messages List */}
          <FlatList
            ref={flatListRef}
            data={messages}
            renderItem={renderMessageItem}
            keyExtractor={(item) => item.id}
            style={styles.messagesList}
            contentContainerStyle={styles.messagesContent}
            onContentSizeChange={() => 
              flatListRef.current?.scrollToEnd({ animated: false })
            }
          />
          
          {/* Input Area */}
          <View style={styles.inputContainer}>
            <TextInput
              style={styles.input}
              value={inputText}
              onChangeText={setInputText}
              placeholder="Type a message..."
              placeholderTextColor="#aaa"
              returnKeyType="send"
              onSubmitEditing={publishMessage}
            />
            <TouchableOpacity
              style={[
                styles.sendButton,
                (!inputText.trim() || !isConnected) && styles.sendButtonDisabled
              ]}
              onPress={publishMessage}
              disabled={!inputText.trim() || !isConnected}
            >
              <Text style={styles.sendButtonText}>Send</Text>
            </TouchableOpacity>
          </View>
        </KeyboardAvoidingView>
      )}
    </SafeAreaView>
  );
}

// Component styles
const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  container: {
    flex: 1,
  },
  loadingContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#555',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  headerText: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
  },
  connectionIndicator: {
    width: 12,
    height: 12,
    borderRadius: 6,
  },
  connected: {
    backgroundColor: '#4CAF50',
  },
  disconnected: {
    backgroundColor: '#F44336',
  },
  messagesList: {
    flex: 1,
    padding: 8,
  },
  messagesContent: {
    paddingBottom: 8,
  },
  messageContainer: {
    padding: 12,
    borderRadius: 16,
    marginVertical: 4,
    maxWidth: '80%',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 1,
    elevation: 1,
  },
  sentMessage: {
    alignSelf: 'flex-end',
    backgroundColor: '#DCF8C6',
    borderBottomRightRadius: 4,
  },
  receivedMessage: {
    alignSelf: 'flex-start',
    backgroundColor: '#fff',
    borderBottomLeftRadius: 4,
  },
  senderText: {
    fontWeight: 'bold',
    fontSize: 13,
    marginBottom: 4,
    color: '#333',
  },
  messageText: {
    fontSize: 15,
    color: '#333',
  },
  timeText: {
    fontSize: 11,
    color: '#999',
    alignSelf: 'flex-end',
    marginTop: 4,
  },
  inputContainer: {
    flexDirection: 'row',
    padding: 12,
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  input: {
    flex: 1,
    height: 40,
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 20,
    paddingHorizontal: 16,
    marginRight: 8,
    backgroundColor: '#fff',
    color: '#333',
  },
  sendButton: {
    height: 40,
    paddingHorizontal: 16,
    borderRadius: 20,
    backgroundColor: '#4b0082',
    justifyContent: 'center',
    alignItems: 'center',
  },
  sendButtonDisabled: {
    backgroundColor: '#B39DDB',
  },
  sendButtonText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});
```

### React

```jsx
// App.jsx
import React, { useState, useRef, useEffect } from 'react';
import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'react-user-' + Math.floor(Math.random() * 1000),
});

export default function App() {
  const [messages, setMessages] = useState([]);
  const [inputText, setInputText] = useState('');
  const [isConnected, setIsConnected] = useState(false);
  const [onlineCount, setOnlineCount] = useState(0);
  const messagesEndRef = useRef(null);

  useEffect(() => {
    pubnub.addListener({
      message: (event) => {
        setMessages((prev) => [...prev, event.message]);
      },
      presence: (event) => {
        // occupancy is present on join/leave/timeout/interval but not on state-change
        if (event.action !== 'state-change') setOnlineCount(event.occupancy);
      },
      status: (event) => {
        if (event.category === 'PNConnectedCategory') {
          setIsConnected(true);
        } else if (event.category === 'PNNetworkIssuesCategory') {
          setIsConnected(false);
        }
      },
    });

    const channel = pubnub.channel('hello_world');
    const subscription = channel.subscription({ receivePresenceEvents: true });
    subscription.subscribe();

    return () => {
      subscription.unsubscribe();
      pubnub.removeAllListeners();
    };
  }, []);

  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  const publishMessage = async () => {
    if (!inputText.trim() || !isConnected) return;

    try {
      await pubnub.publish({
        message: {
          text: inputText,
          sender: pubnub.userId,
          time: new Date().toISOString(),
        },
        channel: 'hello_world',
      });
      setInputText('');
    } catch (error) {
      console.error('Publish failed:', error);
    }
  };

  return (
    <div style={styles.container}>
      <div style={styles.header}>
        <h2 style={styles.title}>PubNub Chat</h2>
        <span style={{ ...styles.badge, background: isConnected ? '#4CAF50' : '#F44336' }}>
          {isConnected ? `${onlineCount} online` : 'Connecting...'}
        </span>
      </div>

      <div style={styles.messageList}>
        {messages.map((msg, i) => (
          <div key={i} style={styles.message}>
            <strong>{msg.sender || 'User'}: </strong>
            {msg.text || JSON.stringify(msg)}
          </div>
        ))}
        <div ref={messagesEndRef} />
      </div>

      <div style={styles.inputRow}>
        <input
          style={styles.input}
          type="text"
          value={inputText}
          onChange={(e) => setInputText(e.target.value)}
          onKeyDown={(e) => e.key === 'Enter' && publishMessage()}
          placeholder="Type a message..."
        />
        <button
          style={{
            ...styles.sendButton,
            opacity: !inputText.trim() || !isConnected ? 0.5 : 1,
          }}
          onClick={publishMessage}
          disabled={!inputText.trim() || !isConnected}
        >
          Send
        </button>
      </div>
    </div>
  );
}

const styles = {
  container: { display: 'flex', flexDirection: 'column', height: '100vh', maxWidth: 600, margin: '0 auto', fontFamily: 'Arial, sans-serif' },
  header: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 16px', borderBottom: '1px solid #e0e0e0' },
  title: { margin: 0, fontSize: 18 },
  badge: { color: '#fff', padding: '4px 10px', borderRadius: 12, fontSize: 13 },
  messageList: { flex: 1, overflowY: 'auto', padding: 16 },
  message: { marginBottom: 8, padding: '8px 12px', background: '#f0f0f0', borderRadius: 8 },
  inputRow: { display: 'flex', padding: 12, borderTop: '1px solid #e0e0e0', gap: 8 },
  input: { flex: 1, padding: '8px 12px', borderRadius: 20, border: '1px solid #ddd', fontSize: 14 },
  sendButton: { padding: '8px 20px', borderRadius: 20, background: '#4b0082', color: '#fff', border: 'none', cursor: 'pointer', fontWeight: 'bold' },
};
```

The examples above showcase complete working code that integrates all the concepts covered in this guide:

* PubNub initialization with proper configuration
* Event listener setup for messages and connection status
* Channel subscription using the entity-based approach
* Message publishing with error handling
* User interface components (where applicable)
* Cleanup and resource management

## Next steps

Great job! 🎉 You've successfully created your first PubNub JavaScript application. Here are some exciting things you can explore next:

### Build chat

* Learn about the [JavaScript Chat SDK](https://www.pubnub.com/docs/chat/chat-sdk) for ready-to-use chat features.
* Add typing indicators and read receipts.

### Advanced features

* Try out [Presence](https://www.pubnub.com/docs/sdks/javascript/api-reference/presence) to track online/offline status.
* Implement [Message Persistence](https://www.pubnub.com/docs/sdks/javascript/api-reference/storage-and-playback) to store and retrieve messages.
* Use [Access Manager](https://www.pubnub.com/docs/sdks/javascript/api-reference/access-manager) to secure your channels.
* Explore [Channel Groups](https://www.pubnub.com/docs/sdks/javascript/api-reference/channel-groups) to organize your channels.

### Real examples

* Explore our GitHub repository for more code samples.
* Follow these tutorials: IoT dashboard, Geolocation app, Delivery app

### More help

* Check out the [SDK reference documentation](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration) for detailed API information.
* Visit the [support portal](https://support.pubnub.com/) for additional resources.
* Ask the AI assistant (the looking glass icon at the top of the page) for help.

## Terms in this document

* **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.
* **PubNub** - PubNub is a real-time messaging platform that provides APIs and SDKs for building scalable applications. It handles the complex infrastructure of real-time communication, including: Message delivery and persistence, Presence detection, Access control, Push notifications, File sharing, Serverless processing with Functions and Events & Actions, Analytics and monitoring with BizOps Workspace, AI-powered insights with Illuminate.
* **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.