--- title: Build a Chat App --- # Build a Chat App In this guide, you will learn how to receive and send messages using Waku by building an app from scratch. If you want to learn how to add Waku to an existing app, check the [Quick Start](./quick-start) guide. ## Pre-Requisites ### 1. Set up Project Setup a new npm package: ```shell mkdir waku-app cd waku-app npm init -y ``` ### 2. Set up Web Server Use the `serve` package as a web server ```shell npm i -D serve ``` Add a `start` script to the `package.json` file: ```json { "scripts": { "start": "serve ." } } ``` ### 3. Create Files Finally, create empty files for your project: ```shell touch index.html index.js ``` ## Write Your App ## 1. Add HTML Elements In `index.html`, add a button, text box and `div` for messages to have a basic chat app. Also, import the `index.js` file. ```html title=index.html Waku Chat App
``` ## 2. Access HTML Elements ::: note From now on, all changes need to be done in the `index.js` file. ::: Initialize variables to easily modify the HTML content: ```js const sendButton = document.getElementById("send") const messagesDiv = document.getElementById("messages") const textInput = document.getElementById("textInput") ``` ## 3. Start a Waku Node Create and start a Waku Node: ```js import {createLightNode} from "https://unpkg.com/@waku/create@0.0.12/bundle/index.js" const wakuNode = await createLightNode({defaultBootstrap: true}) await wakuNode.start() ``` :::info Setting the `defaultBootstrap` option to true allows your Waku node to connect to a set of pre-defined nodes. ::: ## 4. Wait for Connection to be Established Your Waku node needs to connect to a remote node in order to access the network. To wait for this, use the `waitForRemotePeer` function: ```js import * as waku from "https://unpkg.com/@waku/core@0.0.16/bundle/index.js" await waku.waitForRemotePeer(wakuNode) ``` ## 5. Define a Content Topic The `contentTopic` is a metadata `string` used for categorizing messages on the Waku network. Depending on your use case, you can create one or more new `contentTopic`(s). Refer to our [How to Choose a Content Topic](/overview/concepts/content-topics) guide more details. For this guide, we'll use `/chat-app-guide/1/message/utf8`. Note that our payload will be encoded using `utf-8`. We recommended using Protobuf for production purposes. ```js const contentTopic = `/chat-app-guide/1/message/utf8` ``` ## 6. Render Incoming Messages Let's store incoming messages in an array and create a function to render them in the `messages` div: ```js const updateMessages = (msgs, div) => { div.innerHTML = "" } const messages = [] ``` ## 7. Create a Decoder Waku supports various encryption protocols. A decoder allows you to specify the content topic to use and how to decrypt messages. For the chosen content topic, create a plain text decoder (without encryption): ```js const decoder = waku.createDecoder(contentTopic) ``` ## 8. Listen for Incoming Messages Messages sent over the network are `Waku Message`s, as defined in the [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/#wire-format) RFC. Messages returned by the plain text decoder implement the [`DecodedMessage`](https://js.waku.org/classes/_waku_core.DecodedMessage.html) interface. For now, we will just use the `payload` field. It is a byte array field that can be used to encode any data. We will store messages as a `utf-8` string. Listen to messages using the decoder and add them to the `messages` div upon reception: ```ts import * as utils from "https://unpkg.com/@waku/utils@0.0.4/bundle/bytes.js" wakuNode.filter.subscribe([decoder], (message) => { const str = utils.bytesToUtf8(message.payload) messages.push(str) updateMessages(messages, messagesDiv); }) ``` ## 9. Send Messages Finally, create a plain text encoder and set up the `send` button to send messages. Users will be able to enter the message using the `textInput` div. Once done, we can enable the `send` button. ```ts const encoder = waku.createEncoder({contentTopic}) sendButton.onclick = async () => { const text = textInput.value await wakuNode.lightPush.send(encoder, { payload: utils.utf8ToBytes(text), }); textInput.value = null }; sendButton.disabled = false ``` ### 10. Run the App You can now start a local web server to run the app: ```shell npm start ``` Click on the link in the console (http://localhost:3000/) and send a message! You can open your app in several tabs to see messages being sent around. ## Conclusion Congratulations on building your first Waku chat app. You can find the complete files below: ```html title=index.html JS-Waku Quick Start App
``` ```js title=index.js import {createLightNode} from "https://unpkg.com/@waku/create@0.0.12/bundle/index.js" import * as waku from "https://unpkg.com/@waku/core@0.0.16/bundle/index.js" import * as utils from "https://unpkg.com/@waku/utils@0.0.4/bundle/bytes.js" const sendButton = document.getElementById("send") const messagesDiv = document.getElementById("messages") const textInput = document.getElementById("textInput") const wakuNode = await createLightNode({defaultBootstrap: true}) await wakuNode.start() await waku.waitForRemotePeer(wakuNode) const contentTopic = `/chat-app-guide/1/message/utf8` const updateMessages = (msgs, div) => { div.innerHTML = "" } const messages = [] const decoder = waku.createDecoder(contentTopic) wakuNode.filter.subscribe([decoder], (message) => { console.log("message received", message) const str = utils.bytesToUtf8(message.payload) messages.push(str) updateMessages(messages, messagesDiv); }) const encoder = waku.createEncoder({contentTopic}) sendButton.onclick = async () => { const text = textInput.value await wakuNode.lightPush.send(encoder, { payload: utils.utf8ToBytes(text), }) textInput.value = null } sendButton.disabled = false ```