Skip to main content

Command Palette

Search for a command to run...

🧑‍💻 How to Build Real-Time Apps Using HTTP Polling (No WebSockets Needed)

Updated
8 min read
🧑‍💻 How to Build Real-Time Apps Using HTTP Polling (No WebSockets Needed)

Imagine you’re waiting for a bus. You don’t know exactly when it’ll arrive, but you’re eager. You have two choices:

  1. Short polling – keep asking the conductor every 10 seconds, “Has the bus come yet?”
  2. Long polling – ask once, and the conductor says, “I’ll only answer when the bus arrives.”

Both work. Neither involves magical walkie-talkies (WebSockets). And guess what? This is exactly how we can build real-time communication in apps without WebSockets.

In this post, we’ll build a small example using React (frontend) and Node.js (backend), where messages update in “real-time” using short polling and long polling.


🧩 Why Not Just Use WebSockets?

WebSockets are the golden child of real-time apps—fast, persistent, bidirectional. But sometimes you don’t have the luxury:

  • Your infrastructure doesn’t support WebSockets.
  • You want something simpler.
  • You’re running on an old stack where only HTTP is available.

In these cases, polling can still give you that “real-time” feeling.


🔁 Short Polling – The Impatient Way to Do “Real-Time”

Imagine you’re at a restaurant waiting for your order. Instead of sitting quietly, you call the waiter every 2 minutes:

👉 “Is my food ready yet?”

Most of the time, the answer is “Not yet.” But you keep asking until finally, one time the waiter says “Yes!”

That’s short polling in a nutshell.

🧩 What is Short Polling?

Short Polling is a technique where the client repeatedly sends HTTP requests to the server at a fixed interval (e.g., every 2 or 5 seconds) to check if new data is available.

  • If new data exists, the server responds with it.
  • If not, the server just responds with the same old data (or nothing new).

It’s like constantly “refreshing” a page in the background.

⚙️ How Short Polling Works

  1. Client asks the server: “Any new messages?”
  2. Server checks and replies (yes/no).
  3. After a fixed interval, the client asks again.
  4. This cycle repeats forever.

🔄 Flow:

Client ---- Request ----> Server
Client <--- Response ---- Server
(wait a few seconds…)
Client ---- Request ----> Server
Client <--- Response ---- Server

💻 Code Example: Short Polling Chat App

Let’s build a tiny chat-like system with React (frontend) and Node.js (backend).

🖥️ Backend (Node.js + Express)

// short-polling-server.js
const express = require("express");
const cors = require("cors");

const app = express();
app.use(cors());
app.use(express.json());

let messages = ["Hello from server!"];

// Fetch messages
app.get("/messages", (req, res) => {
  res.json(messages);
});

// Post a new message
app.post("/messages", (req, res) => {
  const { text } = req.body;
  messages.push(text);
  res.json({ success: true });
});

app.listen(4000, () =>
  console.log("Short polling server running on port 4000")
);

📱 Frontend (React)

// ShortPollingChat.js
import React, { useEffect, useState } from "react";

export default function ShortPollingChat() {
  const [messages, setMessages] = useState([]);
  const [newMsg, setNewMsg] = useState("");

  // Short polling every 3 seconds
  useEffect(() => {
    const fetchMessages = async () => {
      const res = await fetch("http://localhost:4000/messages");
      const data = await res.json();
      setMessages(data);
    };

    fetchMessages(); // initial fetch
    const interval = setInterval(fetchMessages, 3000); // repeat every 3s
    return () => clearInterval(interval);
  }, []);

  const sendMessage = async () => {
    await fetch("http://localhost:4000/messages", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ text: newMsg }),
    });
    setNewMsg("");
  };

  return (
    <div>
      <h2>Short Polling Chat</h2>
      <div
        style={{
          border: "1px solid gray",
          padding: "10px",
          height: "150px",
          overflowY: "auto",
        }}
      >
        {messages.map((m, i) => (
          <p key={i}>{m}</p>
        ))}
      </div>
      <input
        value={newMsg}
        onChange={(e) => setNewMsg(e.target.value)}
        placeholder="Type message"
      />
      <button onClick={sendMessage}>Send</button>
    </div>
  );
}

✅ Advantages of Short Polling

  • Simplicity – Very easy to implement (basic HTTP requests).
  • Firewall friendly – Works where WebSockets might be blocked.
  • Good for small apps – If updates are rare, this is more than enough.
  • Stateless – Each request is independent, no persistent connections.

❌ Disadvantages of Short Polling

  • Wasted requests – Even when no new data exists, the client still sends requests.
  • Server load – High traffic apps mean lots of unnecessary requests.
  • Latency – Updates depend on the polling interval (e.g., if polling every 5s, worst-case delay is 5s).
  • Not scalable – Becomes inefficient when thousands of clients poll frequently.

📌 Example Use Cases

Short polling is fine for:

  • Notification systems with low activity.
  • Dashboards that refresh occasionally.
  • Hobby projects and prototypes.

But if you’re building WhatsApp, Slack, or live sports updates → you’ll want something more efficient like long polling or WebSockets.


Long Polling – The Patient Way to Do “Real-Time”

Imagine instead of pestering the waiter every 2 minutes about your food, you say:

👉 “I’ll just sit here. Please come tell me when it’s ready.”

The waiter doesn’t respond immediately—he waits until the food is actually ready, and then tells you. That’s long polling.

It feels much closer to real-time communication than short polling, but still uses plain old HTTP requests.

🧩 What is Long Polling?

Long Polling is a technique where:

  1. The client sends an HTTP request to the server.
  2. If new data is not available, the server doesn’t respond immediately—it holds the request open.
  3. As soon as new data is available, the server responds.
  4. The client immediately sends another request, waiting again.

This creates a “loop” where the client is always waiting for new updates.

⚙️ How Long Polling Works

  1. Client sends request → “Any new messages?”
  2. If nothing new → server keeps the connection open.
  3. When new data arrives → server responds immediately.
  4. Client processes the data and instantly opens another request.

🔄 Flow:

Client ---- Request ----> Server (waits…)
Client <--- Response ---- Server (new data)
Client ---- Request ----> Server (waits again…)

💻 Code Example: Long Polling Chat App

We’ll extend our chat example but with long polling logic.

🖥️ Backend (Node.js + Express)

// long-polling-server.js
const express = require("express");
const cors = require("cors");

const app = express();
app.use(cors());
app.use(express.json());

let messages = ["Hello from server!"];
let clients = [];

// Long polling endpoint
app.get("/messages", (req, res) => {
  if (messages.length > 0) {
    // If we already have messages, return them immediately
    res.json(messages);
  } else {
    // Otherwise, keep the connection open until new data arrives
    clients.push(res);
  }
});

// Add new message
app.post("/messages", (req, res) => {
  const { text } = req.body;
  messages.push(text);

  // Notify all waiting clients
  clients.forEach((clientRes) => clientRes.json(messages));
  clients = [];

  res.json({ success: true });
});

app.listen(5000, () => console.log("Long polling server running on port 5000"));

Here’s what’s happening:

  • If there are no messages → the response is stored in clients and kept waiting.
  • When a new message arrives → all waiting clients get the response.

📱 Frontend (React)

// LongPollingChat.js
import React, { useEffect, useState } from "react";

export default function LongPollingChat() {
  const [messages, setMessages] = useState([]);
  const [newMsg, setNewMsg] = useState("");

  useEffect(() => {
    let isMounted = true;

    const poll = async () => {
      try {
        const res = await fetch("http://localhost:5000/messages");
        const data = await res.json();
        if (isMounted) {
          setMessages(data);
          poll(); // Immediately start a new request
        }
      } catch (err) {
        console.error("Polling error", err);
        setTimeout(poll, 2000); // Retry if error happens
      }
    };

    poll();
    return () => {
      isMounted = false;
    };
  }, []);

  const sendMessage = async () => {
    await fetch("http://localhost:5000/messages", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ text: newMsg }),
    });
    setNewMsg("");
  };

  return (
    <div>
      <h2>Long Polling Chat</h2>
      <div
        style={{
          border: "1px solid gray",
          padding: "10px",
          height: "150px",
          overflowY: "auto",
        }}
      >
        {messages.map((m, i) => (
          <p key={i}>{m}</p>
        ))}
      </div>
      <input
        value={newMsg}
        onChange={(e) => setNewMsg(e.target.value)}
        placeholder="Type message"
      />
      <button onClick={sendMessage}>Send</button>
    </div>
  );
}

Now the client isn’t “spamming” the server every 3 seconds. Instead, it sends a request, waits, and only re-requests after getting new data.

✅ Advantages of Long Polling

  • Feels real-time – No waiting for a fixed interval like short polling.
  • Efficient than short polling – Only responds when new data exists.
  • No special protocols – Works with plain HTTP (no WebSockets needed).
  • Firewall friendly – Works even where WebSockets are blocked.

❌ Disadvantages of Long Polling

  • Server resource usage – Many open connections mean higher memory and thread usage.
  • Not truly real-time – Still a workaround, not as efficient as WebSockets.
  • Scaling challenges – With thousands of users, holding connections becomes expensive.
  • Timeout issues – Some proxies/servers may close idle connections, breaking the flow.

📌 Example Use Cases

Long polling is great for:

  • Chat systems with low-to-medium traffic.
  • Stock ticker apps.
  • Notifications (email, social media alerts).
  • Situations where WebSockets aren’t possible.

But again, if you’re building high-scale, real-time systems (gaming, live chat at scale, video streaming)WebSockets or WebRTC are better.


📊 Short Polling vs Long Polling vs WebSockets

FeatureShort Polling 🕑Long Polling ⏳WebSockets ⚡
How It WorksClient sends requests at fixed intervalsClient sends request and server holds connection until new data arrivesPersistent two-way connection between client & server
ComplexityVery simple to implementModerate (needs connection management)Higher (protocols, scaling infra)
LatencyDepends on interval (not truly real-time)Near real-time (server responds instantly when data available)Instant, true real-time
Server LoadHigh – many unnecessary requestsMedium – fewer wasted requests but connections stay openLow – efficient connection handling
ScalabilityPoor for large user basesOkay with optimizationsBest (built for scale)
Best Use CasesSimple dashboards, stock prices refresh, status checksChat apps, notifications, live feedsGaming, trading apps, collaborative editing, video streams
Browser SupportWorks everywhere (plain HTTP)Works everywhere (plain HTTP)Broad support but requires WebSocket-compatible infra
FallbackAlways worksAlways worksNeeds fallback (to polling) if unsupported

🚀 Wrapping Up

Polling may feel “old school,” but sometimes old school still works. If your app doesn’t demand massive real-time updates, short polling and long polling can be surprisingly effective.

But if you’re building the next WhatsApp or Slack? You’ll eventually want WebSockets or WebRTC.

Still, it’s pretty cool to know that even without them, we can fake “real-time.”

Happy coding! 🚀


💬 Have Questions or Suggestions?

Drop a comment below or connect with me on LinkedIn or GitHub. Let’s make apps safer and faster together! 🚀

More from this blog

B

Build Better with Kuntal

19 posts

Practical guides, tips, and tutorials on full-stack development, performance, and mobile apps—helping you build better, faster, and smarter with clean, real-world code. 🚀