Build a Live Chat Room on Vercel

Deploy a live WebSocket chat room on Vercel with reconnecting browser clients.

Introduction

30 Second Summary

A conversation across browser windows quickly falls apart when every new reply needs a manual refresh. Real-time updates keep everyone in sync.

In this project, you will build a live chat room in Node.js for deployment to Vercel. The ws library will carry each message through a WebSocket connection.

What You'll Build

You'll type a message in one browser window, then watch it appear instantly in another before seeing the client reconnect after a deployment interrupts the connection.

By the end of this project, you'll have:

  • A live two-window chat where every sent message appears in both browsers immediately.
  • A deployed Vercel URL that you can open in separate windows to demonstrate real-time messaging on the free Hobby plan.
  • A visible connection lifecycle where you can inspect the HTTP upgrade, find the 101 Switching Protocols response, watch message frames move, and observe automatic reconnection.
  • An optional Secret Mission to push your real-time development skills further.

Are there any prerequisites?

You'll need Node.js, a code editor, and a free Vercel account. Step 1 gets your environment ready.

Before We Start

Your chat room needs a local runtime before it can send a message. It also needs a hosting account before it can reach anyone beyond your computer.

This step prepares each tool before you create any files. A clean setup keeps your first WebSocket test focused on the connection itself.

In this step, get ready to:
  • Prepare your local development tools.
  • Create your Vercel Hobby account.
  • Verify your deployment workflow.
Prepare your local runtime

Node.js runs the chat server on your computer. The Node.js installer also includes npm. You will use this package manager to add the project libraries.

  • Reveal your installed Node.js version plus your npm version by running:
node --version
npm --version

What do these commands check?

  • The first command prints the installed Node.js version.
  • The second command confirms that npm arrived with Node.js.

✔️ I see a supported version

Your Node.js output shows version 18 or higher. npm also prints its own version number.

  • Keep the terminal available for the remaining checks.

ⓧ I see an older version

A Node.js version below 18 does not meet the Vercel CLI prerequisite. The current LTS release gives you a supported runtime with npm included.

  • Visit the official Node.js download page.
  • Select the LTS release for your operating system.
  • Run the downloaded installer.
  • Accept the installer defaults.
  • Close every terminal window after the installation finishes.
  • Open a new terminal through your operating system search.
  • Confirm the new versions by running:
node --version
npm --version

What should you see?

Node.js now prints version 18 or higher. npm prints a separate version number on the next line.

Still seeing the older version?

Close every terminal window so your operating system can refresh its command path. Open a fresh terminal before checking again.

If the older version remains, help me check which Node.js installation my terminal is using.

ⓧ Command not found

Your terminal cannot find Node.js yet. The LTS installer adds Node.js plus npm to your computer.

  • Visit the official Node.js download page.
  • Select the LTS release for your operating system.
  • Run the downloaded installer.
  • Accept the installer defaults.
  • Close every terminal window after the installation finishes.
  • Open a new terminal through your operating system search.
  • Confirm the installation by running:
node --version
npm --version

What should you see?

Both commands now print version numbers. This confirms that your terminal can reach Node.js plus npm.

Commands still missing?

Restart your computer so the installer can finish updating the command path. Run both checks again in a fresh terminal.

If the commands still fail, help me troubleshoot my Node.js installation.

Set up Vercel access

Vercel hosts the chat room when you deploy it later. The Hobby plan provides a free tier for personal projects.

Choosing a plan can feel like a billing commitment. Hobby has no billing cycle. Usage pauses if you exceed its included limits.

  • Open the Vercel sign-up page in your browser.
  • Click Continue with Email.
  • Enter your email address.
  • Type the six-digit one-time password from your inbox.
  • Confirm that your personal account shows the Hobby plan.

Good progress. Your Hobby account is now the destination for the chat room you deploy later.

The Vercel CLI connects your terminal to that account. Checking for it first prevents you from reinstalling a working command.

  • Check whether the Vercel CLI is already available by running:
vercel --version

What does this command check?

The command asks the Vercel CLI to print its installed version. A version number confirms that the command is available from your terminal.

✔️ I see a version number

The Vercel CLI is ready. You can move straight to account authentication.

ⓧ Command not found

The CLI needs to be added through npm. The installation can pause while npm downloads the package.

  • Install the latest Vercel CLI globally by running:
npm install --global vercel@latest
vercel --version

What do these commands do?

  • The first command installs the latest Vercel CLI for your user environment.
  • The second command prints its version to prove the installation succeeded.

Installation did not finish?

Check that the earlier npm version command succeeds. A missing npm command means the Node.js installation still needs attention.

If npm works but the installation fails, help me diagnose my Vercel CLI installation.

The login command starts a browser-based approval flow. The identity check runs after that approval completes.

  • Authenticate the Vercel CLI by running:
vercel login
vercel whoami

What happens during login?

  • The first command asks you to approve terminal access through your browser.
  • The second command prints the username attached to the authenticated account.

Your Vercel username confirms that the terminal can reach your account. No project has been created or deployed.

Login did not complete?

Return to the terminal to find the approval link if your browser did not open automatically. Check the location plus request time before granting access.

If the approval page keeps expiring, help me complete the Vercel CLI login flow.

Prepare your workspace

Two browser tabs act like two people in the chat room. Browser DevTools lets you inspect the connection when the app is running.

  • Install the code editor you plan to use from its official website if needed.
  • Press Cmd+Space on macOS or the Windows key on Windows.
  • Type your code editor's name to open it.
  • Use operating system search again to find your modern browser.
  • Type your browser's name to open it.
  • Use the browser's main menu to open its developer tools.
  • Select the Network tab.
  • Open a second browser tab or window.

Before the final check, what four signals would prove that your runtime plus hosting access are ready?

  • Switch back to the terminal from earlier.
  • Run the complete readiness check:
node --version
npm --version
vercel --version
vercel whoami

What does readiness look like?

  • The first two lines confirm your local JavaScript runtime plus package manager.
  • The third line confirms that the deployment CLI is available.
  • The final line confirms which Vercel account receives future deployments.

You will see three version numbers followed by your Vercel username. That result proves your local tools plus hosting access are ready.

One readiness check failed?

Match the failed line to the earlier check for that tool. Repeat only the relevant installation or login instructions.

For help reading the output, help me identify which setup check failed.

Your development setup is ready. Next, you will create the chat project and watch your first message return through a live WebSocket connection.

Create a Local WebSocket Server

Live chat needs a connection that stays open after the first request. A WebSocket gives the browser a two-way path to the server.

First, a Vercel Function accepts the connection upgrade. The ws library echoes each message to its sender so you can prove the round trip works.

In this step, get ready to:
  • Create a local Node.js project with the ws library.
  • Build a WebSocket endpoint with a one-page browser client.
  • Start the local server and confirm that an echoed message reaches the browser console.
Set up the local project

The project needs a package manifest to record its dependency. npm init -y creates that manifest without an interactive questionnaire.

  • Create the vercel-live-chat project on your Desktop by running these commands:
cd ~/Desktop
mkdir vercel-live-chat
cd vercel-live-chat
npm init -y
npm install ws

What do these commands create?

  • The vercel-live-chat folder keeps every local project file together.
  • The npm init -y command creates package.json with default package details.
  • The npm install ws command adds the WebSocket server library as a project dependency.
  • Confirm that the package files exist by running:
ls

What does this check?

The ls command lists the contents of vercel-live-chat. It confirms that npm created the project files in the intended folder.

You should see package.json, package-lock.json, and node_modules. Your local project now has its WebSocket dependency.

Package files missing?

Check that your terminal path ends in vercel-live-chat. Run the setup commands again from your Desktop if the project was created somewhere else.

If npm cannot install the dependency, confirm that your internet connection is active. Help me fix the local project setup.

  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type the name of your code editor.
  • Press Enter to launch the editor.
  • Use the editor's folder picker to select vercel-live-chat from your Desktop.
Build the echo endpoint

A WebSocket begins as an HTTP request with an Upgrade header. The server accepts that upgrade so future messages can travel over the open connection.

  • Create an api folder inside vercel-live-chat using your editor's file sidebar.
  • Create ws.js inside the api folder.
  • Add the WebSocket endpoint to api/ws.js by pasting this code:
import http from 'http';
import { WebSocketServer } from 'ws';

// Create the HTTP server that receives upgrade requests.
const server = http.createServer();

// Attach ws so upgraded connections can stay open.
const wss = new WebSocketServer({ server });

// Echo each message to the client that sent it.
wss.on('connection', (ws) => {
  ws.on('message', (data) => {
    ws.send(data);
  });
});

export default server;

What does this code do?

  • The HTTP server receives the browser's initial connection request.
  • The WebSocketServer instance handles the connection after the upgrade.
  • The message listener sends the received data back through the same socket.
  • The default export lets Vercel run this server as the function at /api/ws.
  • Save api/ws.js.

The Vercel CLI reproduces the Vercel development environment on your computer. Its local server can run the function while serving the browser page from the same address.

The first run may ask you to authenticate through your browser. Return to the terminal after the sign-in completes.

  • Start the local development server by running:
npx vercel dev --yes

What does this command do?

The command starts Vercel's local development environment. The --yes option accepts the default project setup choices.

Keep this terminal running because it hosts both the page and the WebSocket endpoint.

You should see the local address http://localhost:3000 in the terminal. That address confirms the development server is running.

Local server not starting?

Confirm that the terminal is inside vercel-live-chat. The command needs access to the project's package.json file.

Complete any browser authentication requested by the CLI. Help me troubleshoot Vercel dev.

The server now needs a page that gives you something concrete to send. A fixed sample message keeps the first test focused on the socket round trip.

  • Create index.html inside the top level of vercel-live-chat using your editor's file sidebar.
  • Build the one-page client shell by pasting this code into index.html.
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vercel Live Chat</title>
</head>
<body>
  <!-- Keep the first client simple so the socket behavior stays visible. -->
  <h1>Vercel Live Chat</h1>
  <form id="message-form">
    <input id="message-input" value="Hello WebSocket">
    <button type="submit">Send message</button>
  </form>
  <!-- Load the browser client after the page controls exist. -->
</body>
</html>

What does this page contain?

  • The message-form form groups the input with its send button.
  • The message-input field starts with Hello WebSocket so the first test has a recognizable message.
  • The script comment marks where the browser connection loads after the page controls exist.
  • Save index.html.
  • Open http://localhost:3000 in your browser.

You should see the Vercel Live Chat heading above an input and a Send message button. The local server is now serving your page.

Page not loading?

Confirm that the terminal running the local server is still active. Restart it from vercel-live-chat if the process stopped.

Check that index.html sits directly inside vercel-live-chat. Help me find why the local page is missing.

Connect the browser client

The browser opens its socket as soon as the client script loads. It waits for the connection before letting your form send data.

  • Create client.js inside the top level of vercel-live-chat using your editor's file sidebar.
  • Add the browser connection logic to client.js by pasting this code:
// Match the socket protocol to the page protocol.
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const socket = new WebSocket(`${protocol}://${window.location.host}/api/ws`);

socket.addEventListener('open', () => {
  console.log('WebSocket connected');
});

// Log each echoed message so the round trip is easy to inspect.
socket.addEventListener('message', (event) => {
  console.log('Echo:', event.data);
});

// Send the form value only after the user submits it.
document.querySelector('#message-form').addEventListener('submit', (event) => {
  event.preventDefault();

  const input = document.querySelector('#message-input');
  socket.send(input.value);
});

What's happening here?

  • The protocol value uses ws locally and supports wss when the page uses HTTPS.
  • The open listener records when the connection is ready.
  • The message listener logs data that returns from the server.
  • The form listener sends the input value through the open socket.
  • Save client.js.
  • Return to index.html.
  • Find these lines near the bottom of the file:
  <!-- Load the browser client after the page controls exist. -->
</body>
  • Add the script element below the comment so the lines look like this:
  <!-- Load the browser client after the page controls exist. -->
  <script src="/client.js"></script>
</body>

Why load the script here?

The script loads after the form elements exist in the page. That order lets client.js find the form as soon as it runs.

  • Save index.html.

✔️ Awesome, I've got everything!

Your endpoint and browser client are ready. Double-check that all three files are saved before testing the connection.

ⓧ I'd like to double check the full code

import http from 'http';
import { WebSocketServer } from 'ws';

// Create the HTTP server that receives upgrade requests.
const server = http.createServer();

// Attach ws so upgraded connections can stay open.
const wss = new WebSocketServer({ server });

// Echo each message to the client that sent it.
wss.on('connection', (ws) => {
  ws.on('message', (data) => {
    ws.send(data);
  });
});

export default server;

This function accepts WebSocket connections and echoes each message to its sender.

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vercel Live Chat</title>
</head>
<body>
  <!-- Keep the first client simple so the socket behavior stays visible. -->
  <h1>Vercel Live Chat</h1>
  <form id="message-form">
    <input id="message-input" value="Hello WebSocket">
    <button type="submit">Send message</button>
  </form>
  <!-- Load the browser client after the page controls exist. -->
  <script src="/client.js"></script>
</body>
</html>

This page provides the message form and loads the browser client after the controls.

// Match the socket protocol to the page protocol.
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const socket = new WebSocket(`${protocol}://${window.location.host}/api/ws`);

socket.addEventListener('open', () => {
  console.log('WebSocket connected');
});

// Log each echoed message so the round trip is easy to inspect.
socket.addEventListener('message', (event) => {
  console.log('Echo:', event.data);
});

// Send the form value only after the user submits it.
document.querySelector('#message-form').addEventListener('submit', (event) => {
  event.preventDefault();

  const input = document.querySelector('#message-input');
  socket.send(input.value);
});

This client opens the socket and sends the form value through it. It logs every echoed reply in the browser console.

The final check follows one message through the complete connection. DevTools lets you see the connection confirmation and echoed reply without adding more page code.

  • Press Cmd+Option+I on macOS or Ctrl+Shift+I on Windows to open DevTools.
  • Select the Console tab.
  • Refresh http://localhost:3000.

You should see WebSocket connected in the console. That line proves the browser completed the connection upgrade.

Before you send the message, where do you expect the server's reply to appear?

  • Click Send message.

You should see Echo: followed by Hello WebSocket in the console. Your first message has completed a live browser-to-server round trip.

Echo missing from the console?

Confirm that the local development server is still running. Refresh the page after restarting it so the browser creates a new socket.

Check that the endpoint is saved as api/ws.js. Check that the client connects to /api/ws.

If the connection succeeds but the reply stays missing, compare the message listener in both JavaScript files. Help me debug the missing WebSocket echo.

Your local echo path works from end to end. Next, you will turn that one-sender reply into a broadcast that reaches every connected tab.

Broadcast Messages to Local Tabs

Your local WebSocket endpoint already echoes each message to its sender. That proves the browser can keep a connection open with your server.

A chat room needs every connected browser to receive the same message. The ws library tracks those connections so your endpoint can broadcast across them.

In this step, get ready to:
  • Replace the sender-only echo with a broadcast to every open client.
  • Confirm the original browser tab still receives its own message.
  • Prove that two local tabs receive the same messages.
Broadcast each received message

The server already receives messages inside its connection handler. You only need to change where each received message goes.

  • Switch back to the WebSocket endpoint file in your code editor.
  • Find the existing message handler that sends received data back through the same connection.
  • Replace that complete message handler with the code below:
ws.on('message', function message(data, isBinary) {
  // Share each message with every connection that can receive it
  wss.clients.forEach(function each(client) {
    if (client.readyState === WebSocket.OPEN) {
      client.send(data, { binary: isBinary });
    }
  });
});

What does this code do?

  • The wss.clients collection holds the connections tracked by the WebSocket server.
  • The WebSocket.OPEN check selects clients that are ready to receive data.
  • The client.send() call forwards the received message to each ready client.
  • The { binary: isBinary } option preserves the message format during the broadcast.
  • Save the WebSocket endpoint file.
  • Return to the first local browser tab from the previous step.
  • Refresh the local chat page.
  • Send first broadcast through the same client control you used earlier.

You should see first broadcast logged once in the browser console. This confirms the new handler still includes the sending client.

Message stopped returning?

Check that the new handler remains inside the existing connection callback. The ws connection must be available there.

Confirm that the sender-only call from the old handler has been removed. Keep the surrounding HTTP upgrade code unchanged.

Save the endpoint file again if your local server did not reload the change.

Help me debug why my WebSocket broadcast handler stopped returning messages.

✔️ Awesome, I've got everything!

Your endpoint now sends each received message to every open connection.

ⓧ I'd like to double check the full code

The complete changed message handler should match this reference.

ws.on('message', function message(data, isBinary) {
  // Share each message with every connection that can receive it
  wss.clients.forEach(function each(client) {
    if (client.readyState === WebSocket.OPEN) {
      client.send(data, { binary: isBinary });
    }
  });
});
Prove the broadcast across two tabs

A broadcast becomes visible when multiple clients stay connected at the same time. Two local tabs give you a small chat room without changing the browser client.

  • Copy the local chat page address from the first browser tab.
  • Create a second browser tab.
  • Paste the copied address into the second tab's address bar.
  • Press Enter to load the second client.

You should see a second copy of the local chat page. Both tabs now hold separate connections to the same endpoint.

  • Open the browser console for the first tab.
  • Open the browser console for the second tab.
  • Before you send the next message, make a quick prediction about whether one console or both consoles will receive it.
  • Return to the first browser tab.
  • Send hello from tab one through the chat client.

You should see hello from tab one in both browser consoles. One incoming message has reached two connected clients.

  • Return to the second browser tab.
  • Send hello from tab two through the chat client.

You should see hello from tab two in both browser consoles. That is the local fan-out working in both directions.

Only one tab receiving messages?

Confirm that both tabs use the same local chat page address. A different port points to a different local server.

Refresh the second tab if it connected before the endpoint reloaded. This gives the tab a fresh connection to the updated handler.

Check that the loop sends to every ready client. A condition that excludes the sender changes what each console receives.

Help me find why only one local browser tab receives my broadcast messages.

Your local chat room now fans one message out to every connected tab. Next, you will deploy it to your Vercel URL so browser windows can use the live endpoint.

Deploy the Chat Room to Vercel

Your chat room already broadcasts messages between local browser tabs. That result still depends on the development server running on your computer.

Now you'll deploy the browser client through a Vercel Function. You'll deploy its WebSocket endpoint at the same time. A production URL gives your two browser tabs a hosted meeting point.

In this step, get ready to:
  • Connect the Vercel CLI to your Hobby account.
  • Deploy the local project to a production URL.
  • Verify that two deployed tabs receive each other's messages.
Sign in to Vercel

The Vercel CLI uses a browser approval flow to connect your terminal to your account. Account approval deserves a careful pause because it grants this terminal access.

  • Return to the terminal that is running the local vercel-live-chat server.
  • Stop the local development server by pressing Ctrl+C.
  • Start the browser approval flow by running this command:
vercel login

What does this command do?

  • The vercel login command starts Vercel's browser approval flow.
  • A successful approval gives later deployment commands permission to use your account.
  • Open the verification URL if the terminal prints one.
  • Review the request details on the approval page.
  • Approve the request using the page's approval control.
  • Return to the terminal after the browser confirms approval.

Your terminal confirms that authentication is complete. Good progress. The CLI can now create deployments under your Hobby account.

Having trouble signing in?

  • Return to the Vercel CLI setup from earlier if your shell cannot find the command. Use the npx route established during that setup.
  • Rerun the login command if the browser approval page has expired.

Ask for help with a Vercel CLI login that will not complete.

Deploy the production project

A production deployment links your local vercel-live-chat folder to a hosted project. The first run may ask a few setup questions before it starts building.

This small chat test stays within the Hobby plan's included Function allowances.

  • Create the production deployment by running this command:
vercel --prod

What does this command do?

  • The vercel --prod command creates a production deployment.
  • The first deployment links the current folder to a Vercel project.
  • A successful deployment prints the URL that serves your live chat room.
  • Select your Hobby account if the CLI asks for a project scope.
  • Choose the option that creates a new project.
  • Enter vercel-live-chat as the project name.
  • Choose the current folder as the source directory.
  • Keep the detected project settings.

The first production build can take a few minutes while Vercel packages the client and Function.

  • Wait for the production deployment to finish.

Your chat room now has a production home. The CLI prints its deployment URL when the build succeeds.

  • Record the production deployment URL here: https://your-project.vercel.app.

Deployment did not finish?

  • Confirm the terminal is still inside the vercel-live-chat folder.
  • Read the first build error in the terminal to identify which earlier project dependency needs attention.

Ask for help with a failing Vercel production deployment.

Test the live broadcast

Your local test proved that one server process could share messages between connected clients. This hosted test proves that the browser client reaches the deployed WebSocket endpoint.

  • Return to the two browser tabs from your local chat test.
  • Navigate the first tab to https://your-project.vercel.app.
  • Navigate the second tab to https://your-project.vercel.app.

Both tabs should display the deployed chat client with an active connection.

Before you send the first message, do you expect one deployed tab or both deployed tabs to receive it?

  • Enter Hello from production in the first tab's chat message field.
  • Submit the message using the chat form's send control.

You'll see Hello from production appear in both deployed tabs. The hosted Function has broadcast the message to both open connections.

  • Enter Reply from the second tab in the second tab's chat message field.
  • Submit the reply using the chat form's send control.

You'll see the reply appear in both tabs. That's the live deployment working in both directions.

One tab missing messages?

This prototype stores connected clients in one Function instance. Two connections can occasionally reach different instances after a fresh deployment.

  • Reload both production pages within a few seconds of each other.
  • Confirm both address bars show the production deployment URL printed by the CLI.
  • Send a fresh message after both chat pages show an active connection.

Ask for help with deployed chat tabs that do not receive the same broadcast.

Your chat room is live at its own production URL. Next, you'll inspect the open connection to see its HTTP upgrade and message frames.

Inspect the WebSocket Connection

Your deployed Vercel chat room already proves that messages travel between two browser tabs. The network exchange behind that result is still hidden.

A WebSocket connection begins with an HTTP handshake. The browser asks the server to keep that connection open for realtime traffic.

In this step, you will use browser DevTools to inspect the upgrade response. You will also watch chat messages travel across the open connection.

In this step, get ready to:
  • Capture the WebSocket request in the Network panel.
  • Inspect the response that upgrades the connection.
  • Follow chat message frames over the open connection.
Capture the connection request

The Network panel records requests that happen while it is open. Reloading the deployed page gives you a fresh WebSocket handshake to inspect.

  • In one deployed chat tab, open your browser's developer tools.
  • Select the Network tab.
  • Reload the deployed chat page.

You'll see a fresh set of network requests. One request remains active because it carries the WebSocket connection.

Can't find the connection?

  • Make sure the Network tab was selected before you reloaded the page.
  • Reload the deployed chat page again with DevTools still open.

Help me find the WebSocket request in my browser's Network panel.

Confirm the protocol upgrade

The browser starts the connection as an HTTP request. The server response determines whether the connection upgrades or completes.

Before you inspect the response, pause on one prediction: whether the server accepted the upgrade or completed the request normally.

  • Select the request that remains active after the page reload.
  • Inspect the response status shown in the selected request's details.

You'll see 101 Switching Protocols for the response. The browser now keeps the connection open for WebSocket traffic.

What Does 101 Mean?

The 101 Switching Protocols response confirms that the server accepted the browser's upgrade request. The original HTTP request has switched to the WebSocket protocol.

This connection can carry traffic in both directions while it remains open. Each message can travel through the existing connection.

Watch messages cross the connection

After the upgrade, chat data travels in WebSocket message frames. DevTools groups those frames under the selected open request.

Before you send the first message, pause on one prediction: whether DevTools creates a separate request or adds a frame to the connection that is already open.

  • Keep the selected WebSocket request visible in the first tab's DevTools.
  • Switch back to the second deployed chat tab.
  • Type network-check-inbound into the chat message field.
  • Send the message.
  • Return to the first deployed chat tab.

You'll see network-check-inbound in the first chat tab. DevTools adds a new message frame under the open connection.

Before you send a reply, pause on one prediction: whether the original WebSocket request remains open while another frame is added.

  • Type network-check-outbound into the first tab's chat message field.
  • Send the reply.
  • Inspect the selected connection's message list in DevTools.

You'll see network-check-outbound in both chat tabs. The still-open request now lists both message exchanges as frames.

Frames missing?

  • Confirm that the selected request shows 101 Switching Protocols.
  • Send another chat message after selecting the open request.
  • Keep the Network panel open while the message travels.

Help me find the missing WebSocket message frames in DevTools.

Strong work: you have traced your live chat from its HTTP handshake to its WebSocket frames. Next, you will add reconnect logic so the browser can recover when this open connection drops.

Add Automatic Reconnection

Your deployed chat already proves that two browser tabs can share messages over a WebSocket connection. A new deployment can end that open connection.

In this step, you will add an automatic retry loop with backoff to the browser client. You will redeploy the chat on Vercel to test how the client recovers.

In this step, get ready to:
  • Restructure the browser client so closed connections trigger a retry loop.
  • Redeploy the updated chat to close the existing connection.
  • Prove that both browser tabs reconnect before exchanging another message.
Add the reconnect loop

A reconnect loop turns connection loss into a temporary pause. Backoff increases the wait between repeated attempts.

How does the retry loop work?

  • A reusable connection routine opens the WebSocket connection.
  • The close handler schedules another call to that routine after the current retry delay.
  • Each failed attempt increases the retry delay.
  • A successful connection resets the retry delay.
  • Switch back to the code editor from earlier.
  • Select the file that contains the one-page browser client.
  • Locate the current one-shot WebSocket connection setup.
  • Replace that setup with the reusable retry-loop structure described above.
  • Save the browser client file.

✔️ Awesome, I've got everything!

Your saved browser client now creates connections through one reusable routine. A closed connection schedules another attempt with a longer delay.

ⓧ I'd like to double check the full code

Compare the full browser client against these structural checks.

  • Confirm that the reusable connection routine assigns each new WebSocket to the reference used by the message submission logic.
  • Confirm that the close handler schedules another call to the connection routine.
  • Confirm that the close handler increases the retry delay after scheduling the next attempt.
  • Confirm that the open handler resets the retry delay after a successful connection.
Redeploy the updated client

The deployed browser tabs still hold their original WebSocket connections. Redeploying gives you a controlled way to close those connections.

Before you redeploy, how many WebSocket requests do you expect to see after the retry loop responds to the closed connection?

  • Keep the Network tab in browser DevTools visible.
  • Trigger a production redeployment using the same deployment method from earlier.
  • Wait for the production deployment to finish.

You will see the old WebSocket request close. A fresh WebSocket request appears after the backoff pause.

The fresh request receives a 101 Switching Protocols response. That new upgrade proves the retry routine opened another live connection.

No fresh WebSocket request?

  • Confirm that the close handler belongs to the active WebSocket created by the reusable connection routine.
  • Confirm that the close handler calls the connection routine after the retry delay.
  • Confirm that the updated browser client was included in the production deployment.

Ask for help with the retry path if the connection stays closed: Help me debug why my WebSocket client does not reconnect after a Vercel redeployment.

Prove the chat rejoins

Before you send another message, do you think both browser tabs have rejoined a live connection?

  • Wait for the fresh WebSocket request in both deployed chat tabs to show 101 Switching Protocols.
  • Send a new chat message from the first deployed tab.
  • Switch to the second deployed tab.

You should see the new message in both tabs. The successful broadcast proves that each client rejoined after the redeployment.

  • Return to the Network tab in the first browser tab.
  • Select the fresh WebSocket request.
  • Check its message frames for the message you just sent.

You should see the new chat message among the frames on the replacement connection.

That reliability upgrade is working. Your chat now recovers from a deployment interruption before resuming live broadcasts.

Next, you will return to the Vercel dashboard to connect this open WebSocket with the function logs and usage behind it.

Review Function Logs and Usage

Your deployed chat now survives an interrupted connection. The next goal is to see what Vercel records behind that working browser experience.

Runtime logs expose the request that opens each WebSocket connection. Usage charts connect that request to the function resources behind your live chat.

In this step, get ready to:
  • Generate fresh activity from the connected chat.
  • Locate the WebSocket function request in the runtime logs.
  • Review function usage while the chat connections remain active.
Create a fresh request trail

Fresh browser activity gives you a recent request to find in the dashboard. Both deployed chat tabs are already connected from the previous step.

  • Switch back to one deployed chat tab.
  • Send checking function activity in the chat.
  • Switch to the second deployed chat tab.
  • Confirm that checking function activity appears there.
  • Leave both deployed chat tabs open.

Your live broadcast still works. The open tabs now provide current activity for the dashboard checks.

Inspect the runtime logs

Runtime logs group activity by function request. The WebSocket upgrade gives you the request that owns the open connection.

  • Return to your Vercel dashboard from earlier.
  • Select the vercel-live-chat project.
  • Select Logs in the project sidebar.
  • Choose production in the Environment filter.
  • Choose Vercel Functions in the Resource filter.
  • Turn on Live mode.

Before you refresh the chat, what new activity do you expect the Logs view to capture?

  • Switch back to one deployed chat tab.
  • Refresh that chat tab.
  • Return to Logs.

You'll see a recent function request associated with the refreshed WebSocket connection.

  • Select the newest function log row.

The details panel identifies the Function. It also identifies the production Deployment.

Why doesn't every message create a new request?

The browser sends chat messages as frames over the upgraded connection. A message does not start a new function request.

Platform logs center on the function invocation that owns the connection. Browser DevTools remains the clearest place to inspect individual message frames.

Can't find a recent function log?

  • Set the Environment filter to production.
  • Set the Resource filter to Vercel Functions.
  • Reload one deployed chat tab while Live mode is enabled.

Still missing the request? Help me find my WebSocket function request in Vercel runtime logs.

Review function usage

Observability turns individual requests into project-level metrics. This view connects the working chat session to its function resource usage.

  • Select Observability in the project sidebar.
  • Select Vercel Functions.
  • Set the time range to include the activity you just generated.

Before you expand the charts, which metric do you expect to connect most directly to the function request you found in Logs?

  • Expand Vercel Functions using the chevron.
  • Locate the Invocations chart.
  • Locate the Active CPU chart.
  • Locate the Provisioned Memory chart.

You'll see project-level function activity across these charts. With only two chat tabs, the values can be small.

What does the usage view prove?

Invocations connect your browser activity to requests handled by the function. Active CPU shows the compute used while the function performs work.

Provisioned Memory shows the memory allocated during execution. Together, these charts give you the operational view behind the live chat.

Usage charts look empty?

  • Set the time range to include your latest chat activity.
  • Reload one deployed chat tab.
  • Return to Observability.
  • Check Vercel Functions again.

Need help matching the activity to the charts? Help me understand my Vercel Functions usage view.

That's the operational picture complete. Your live chat now has request logs plus function usage metrics.

Secret mission

Audit Message Loss During a Disconnect

Disconnect one browser tab while another stays online. Prove that reconnecting restores future delivery without recovering a missed message. Then outline the durable history layer a production chat room needs.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep the live WebSocket chat room, pause its active connections, or delete its resources. The main path stays at $0 on Vercel's Hobby plan while usage remains within its function and data transfer allowances.

Resources you used:

  • Local vercel-live-chat Node.js project folder.
  • Vercel project vercel-live-chat with its production deployment.

Keep everything running

Leave everything intact if you want the production URL ready for another demonstration. Open connections continue using Hobby plan allowances while someone has the chat room open.

  • Keep the local vercel-live-chat folder for future changes.
  • Keep the Vercel project so its production URL remains available.
  • Leave your browser tabs connected when you want the live chat room active.

Pause - I'll come back to this later

Pausing active use closes your browser connections while preserving the local folder. The deployed project remains available for your return.

  • Close both browser windows or tabs showing the deployed chat room.
  • Stop any local chat server process that is still running.
  • Leave the local vercel-live-chat folder untouched.
  • Leave the Vercel project untouched.

With the chat room tabs closed, your browser no longer holds open connections to the deployed endpoint.

Delete - I don't want to use this again

Deletion is permanent, but the deployed project and local folder are separate resources. Removing the Vercel project leaves your local vercel-live-chat folder available until you delete it separately.

  • Close both browser windows or tabs showing the deployed chat room.
  • Return to the vercel-live-chat project in the Vercel dashboard from earlier.
  • Open the project's settings page.
  • Find the project deletion control.
  • Use the deletion control for vercel-live-chat.
  • Complete the confirmation requested by Vercel.
  • Return to the dashboard's project list.

That is the hosted side cleaned up. You should no longer see vercel-live-chat in the project list.

The local folder needs its own deletion because it lives on your computer.

macOS

  • Press Cmd+Space to open macOS search.
  • Type Finder into the search bar.
  • Press Enter to open Finder.
  • Search for vercel-live-chat using Finder's search field.
  • Right-click the matching project folder to open its context menu.
  • Choose the menu action that removes the folder from your computer.
  • Clear the folder from the macOS trash to make the removal permanent.

Windows

  • Press the Windows key to open Windows search.
  • Type File Explorer into the search bar.
  • Press Enter to open File Explorer.
  • Search for vercel-live-chat using File Explorer's search field.
  • Right-click the matching project folder to open its context menu.
  • Choose the menu action that removes the folder from your computer.
  • Clear the folder from the Windows deleted-items area to make the removal permanent.
  • Search for vercel-live-chat again in the same file manager.

The search should return no matching local project folder. Cleanup complete. Your deployed project and local project files are now removed.

Still Seeing a Project Resource?

  • Refresh the Vercel project list after completing the deletion confirmation.
  • Repeat the local deletion from the actual folder location if your search result is only a recent shortcut.
  • Help me finish cleaning up this project.

Nice Work!

Nice Work!

You made it! Your Vercel chat room now shares messages live across browser tabs through an open WebSocket connection.

You've learned how to:

  • Built a live chat room that broadcasts each message to every connected browser tab.
  • Confirmed the HTTP upgrade by finding 101 Switching Protocols in browser DevTools. Followed live message frames over the open connection. Located the active function logs in the Vercel dashboard. Checked usage while connections stayed open.
  • Added automatic reconnects with backoff. Proved the browser can rejoin after a deployment interruption.
  • Secret Mission: Extended the chat room through an optional challenge that pushed your realtime WebSocket skills further.

Ready to quiz yourself?