Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home IoT & Smart Home

ESP32 HTTP Server: Host a Web Dashboard on Your Device

ESP32 HTTP Server: Host a Web Dashboard on Your Device

March 11, 2026 /Posted byJayesh Jain / 0

One of the most exciting capabilities of the ESP32 is its ability to act as a full ESP32 HTTP web server dashboard — hosting a live, interactive control panel that any device on your local network can access through a browser. No cloud, no app, no subscription. This tutorial walks you through building a production-quality web dashboard on your ESP32 using ESPAsyncWebServer, covering everything from basic GET/POST handling to real-time WebSocket data streaming.

Table of Contents

  1. Why Use ESPAsyncWebServer?
  2. Setting Up Your First HTTP Server
  3. Serving HTML/CSS/JS from LittleFS
  4. Building a REST API for Sensor Data
  5. Real-Time Updates with WebSockets
  6. Complete Dashboard HTML Example
  7. Frequently Asked Questions

Why Use ESPAsyncWebServer?

The ESP32’s built-in WebServer library (from the Arduino framework) is synchronous — it blocks the main loop while handling requests. For a simple demo, this works. For any real project, it creates problems: your sensor readings freeze while serving a web page, and concurrent requests cause timeouts.

ESPAsyncWebServer solves this by running the web server in a separate FreeRTOS task, using asynchronous I/O. Your loop() continues running normally. The library also supports WebSockets, Server-Sent Events (SSE), multipart file uploads, and automatic GZIP handling — features that would require significant custom code otherwise.

Installing Required Libraries

In Arduino IDE, install these libraries via the Library Manager:

  • ESPAsyncWebServer by lacamera or me-no-dev
  • AsyncTCP (for ESP32)
  • ArduinoJson by Benoit Blanchon (for JSON responses)
Ai Thinker NodeMCU-32S-ESP32 Development Board

Ai Thinker NodeMCU-32S-ESP32 Development Board – IPEX Version

The dual-core ESP32 with WiFi is perfect for running an async web server and reading sensors simultaneously without lag or blocking.

View on Zbotic

Setting Up Your First HTTP Server

Let’s start with a minimal but functional server that demonstrates the core patterns you’ll use throughout this tutorial:

#include <WiFi.h>
#include <ESPAsyncWebServer.h>

const char* SSID = "Your_WiFi";
const char* PASS = "Your_Password";

AsyncWebServer server(80);

void setup() {
  Serial.begin(115200);
  
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("nIP: " + WiFi.localIP().toString());
  
  // Route: GET /
  server.on("/", HTTP_GET, [](AsyncWebServerRequest* req) {
    req->send(200, "text/html", 
      "<h1>ESP32 Dashboard</h1>"
      "<p>Server is running!</p>");
  });
  
  // Route: GET /status (returns JSON)
  server.on("/status", HTTP_GET, [](AsyncWebServerRequest* req) {
    String json = "{"uptime":" + String(millis()/1000) + 
                  ","heap":" + String(ESP.getFreeHeap()) + "}";
    req->send(200, "application/json", json);
  });
  
  // Route: POST /control
  server.on("/control", HTTP_POST, [](AsyncWebServerRequest* req) {
    if (req->hasParam("pin", true) && req->hasParam("state", true)) {
      int pin = req->getParam("pin", true)->value().toInt();
      int state = req->getParam("state", true)->value().toInt();
      digitalWrite(pin, state);
      req->send(200, "application/json", "{"ok":true}");
    } else {
      req->send(400, "application/json", "{"error":"Missing params"}");
    }
  });
  
  // 404 handler
  server.onNotFound([](AsyncWebServerRequest* req) {
    req->send(404, "text/plain", "Not found");
  });
  
  server.begin();
}

void loop() {
  // Sensor reading, business logic, etc.
  delay(10);
}

Serving HTML/CSS/JS from LittleFS

Instead of embedding HTML as strings in your sketch, store proper files in LittleFS. This makes your dashboard much easier to develop and update:

#include "LittleFS.h"

// In setup():
if (!LittleFS.begin(true)) {
  Serial.println("LittleFS failed!");
  return;
}

// Serve entire /data directory as web root
// Files: data/index.html, data/style.css, data/app.js
server.serveStatic("/", LittleFS, "/")
      .setDefaultFile("index.html")
      .setCacheControl("max-age=600");  // Cache 10 minutes

// Dynamic endpoints still work alongside static files
server.on("/api/sensors", HTTP_GET, handleSensors);

With GZIP compression, you can pre-compress your HTML, CSS, and JS files offline and upload the .gz versions. ESPAsyncWebServer automatically serves gzipped files with the correct Content-Encoding: gzip header, reducing transfer sizes by 60-80% and making the dashboard load faster.

// Serve pre-compressed files
server.on("/app.js", HTTP_GET, [](AsyncWebServerRequest* req) {
  AsyncWebServerResponse* resp = 
    req->beginResponse(LittleFS, "/app.js.gz", "text/javascript");
  resp->addHeader("Content-Encoding", "gzip");
  req->send(resp);
});

Building a REST API for Sensor Data

A well-structured REST API separates your dashboard’s data from its presentation. Here’s a complete sensor API handler using ArduinoJson:

#include <ArduinoJson.h>
#include "DHT.h"

DHT dht(4, DHT11);  // Data pin 4

void handleSensors(AsyncWebServerRequest* req) {
  JsonDocument doc;
  
  doc["temperature"] = dht.readTemperature();
  doc["humidity"] = dht.readHumidity();
  doc["uptime_s"] = millis() / 1000;
  doc["free_heap"] = ESP.getFreeHeap();
  doc["wifi_rssi"] = WiFi.RSSI();
  
  // Add timestamp
  doc["timestamp"] = millis();
  
  String output;
  serializeJson(doc, output);
  
  // Add CORS headers for browser access
  AsyncWebServerResponse* resp = 
    req->beginResponse(200, "application/json", output);
  resp->addHeader("Access-Control-Allow-Origin", "*");
  req->send(resp);
}

// Register in setup():
// server.on("/api/sensors", HTTP_GET, handleSensors);
DHT11 Temperature And Humidity Sensor Module with LED

DHT11 Temperature And Humidity Sensor Module with LED

The classic sensor for ESP32 web dashboards — pair it with your web server to display live temperature and humidity on any browser.

View on Zbotic

Real-Time Updates with WebSockets

Polling the API every second works but wastes bandwidth and adds latency. WebSockets provide a persistent bidirectional connection — the ESP32 pushes data to all connected browsers the moment it changes.

#include <ESPAsyncWebServer.h>

AsyncWebServer server(80);
AsyncWebSocket ws("/ws");  // WebSocket endpoint

void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client,
               AwsEventType type, void* arg, uint8_t* data, size_t len) {
  if (type == WS_EVT_CONNECT) {
    Serial.printf("Client #%u connectedn", client->id());
    // Send welcome message
    client->text("{"type":"connected"}");
  } else if (type == WS_EVT_DISCONNECT) {
    Serial.printf("Client #%u disconnectedn", client->id());
  } else if (type == WS_EVT_DATA) {
    // Handle incoming commands from browser
    AwsFrameInfo* info = (AwsFrameInfo*)arg;
    if (info->final && info->index == 0 && 
        info->len == len && info->opcode == WS_TEXT) {
      String msg = String((char*)data).substring(0, len);
      Serial.println("WS received: " + msg);
      // Parse command and control GPIO, etc.
    }
  }
}

void setup() {
  ws.onEvent(onWsEvent);
  server.addHandler(&ws);
  server.begin();
}

void loop() {
  // Clean up disconnected clients
  ws.cleanupClients();
  
  // Broadcast sensor data every 2 seconds
  static unsigned long lastBroadcast = 0;
  if (millis() - lastBroadcast > 2000) {
    lastBroadcast = millis();
    float temp = dht.readTemperature();
    String json = "{"type":"sensor","temp":" + 
                   String(temp, 1) + "}";
    ws.textAll(json);  // Send to all connected clients
  }
}

Complete Dashboard HTML Example

Here’s a complete single-file dashboard that connects to the WebSocket, displays live sensor data, and allows GPIO control. Save this as data/index.html in your sketch:

<!DOCTYPE html>
<html><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP32 Dashboard</title>
<style>
  * { box-sizing: border-box; }
  body { font-family: 'Segoe UI', sans-serif; margin: 0; 
         background: #1a1a2e; color: #eee; }
  .header { background: #16213e; padding: 20px; text-align: center;
             border-bottom: 2px solid #ff6b00; }
  .header h1 { margin: 0; color: #ff6b00; }
  .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
           gap: 20px; padding: 20px; }
  .card { background: #16213e; border-radius: 12px; padding: 20px;
           text-align: center; border: 1px solid #0f3460; }
  .card .value { font-size: 48px; font-weight: bold; color: #ff6b00; }
  .card .label { font-size: 14px; color: #aaa; margin-top: 5px; }
  .status { display: inline-block; width: 12px; height: 12px; 
             border-radius: 50%; background: #4caf50; margin-right: 8px; }
  .btn { padding: 10px 20px; border: none; border-radius: 6px;
          cursor: pointer; font-size: 14px; margin: 5px; }
  .btn-on { background: #4caf50; color: white; }
  .btn-off { background: #f44336; color: white; }
</style>
</head><body>
<div class="header">
  <h1>ESP32 Dashboard</h1>
  <p><span class="status" id="dot"></span><span id="status">Connecting...</span></p>
</div>
<div class="grid">
  <div class="card">
    <div class="value" id="temp">--</div>
    <div class="label">Temperature (degC)</div>
  </div>
  <div class="card">
    <div class="value" id="hum">--</div>
    <div class="label">Humidity (%)</div>
  </div>
  <div class="card">
    <div class="value" id="uptime">--</div>
    <div class="label">Uptime (s)</div>
  </div>
</div>
<div style="padding: 20px">
  <h3>GPIO Control</h3>
  <button class="btn btn-on" onclick="sendCmd('gpio',2,1)">LED ON</button>
  <button class="btn btn-off" onclick="sendCmd('gpio',2,0)">LED OFF</button>
</div>
<script>
  const ws = new WebSocket(`ws://${location.host}/ws`);
  ws.onopen = () => {
    document.getElementById('status').textContent = 'Connected';
    document.getElementById('dot').style.background = '#4caf50';
  };
  ws.onclose = () => {
    document.getElementById('status').textContent = 'Disconnected';
    document.getElementById('dot').style.background = '#f44336';
  };
  ws.onmessage = (e) => {
    const d = JSON.parse(e.data);
    if (d.type === 'sensor') {
      document.getElementById('temp').textContent = d.temp?.toFixed(1) ?? '--';
      document.getElementById('hum').textContent = d.hum?.toFixed(0) ?? '--';
      document.getElementById('uptime').textContent = d.uptime ?? '--';
    }
  };
  function sendCmd(type, pin, state) {
    ws.send(JSON.stringify({type, pin, state}));
  }
</script>
</body></html>
DHT20 SIP Packaged Temperature and Humidity Sensor

DHT20 SIP Packaged Temperature and Humidity Sensor

The upgraded DHT20 with I2C interface and better accuracy — perfect for your ESP32 web dashboard project for precision environmental monitoring.

View on Zbotic

4 x 18650 Lithium Battery Shield

4 x 18650 Lithium Battery Shield for ESP32/ESP8266

Power your ESP32 web dashboard server portably — this 4-cell 18650 shield with 5V USB output keeps your dashboard running for hours without mains power.

View on Zbotic

Frequently Asked Questions

How many simultaneous connections can the ESP32 web server handle?

The ESP32 can handle approximately 4-8 simultaneous TCP connections for web serving. ESPAsyncWebServer is more efficient than blocking servers and can handle bursts of requests well. For WebSocket connections, memory is the limiting factor — each client uses ~1-2 KB RAM, so with 320 KB RAM available (after WiFi stack), you can support 10-20 concurrent WebSocket clients comfortably.

Can I use HTTPS on the ESP32 web server?

Yes, but it requires significant resources. Use the AsyncWebServer with a TLS context using Espressif’s esp_tls component. Self-signed certificates work for local use but browsers will show a security warning. Alternatively, use HTTP locally (on a trusted LAN) and set up an HTTPS reverse proxy with Nginx on a Raspberry Pi or router for external access.

How do I make the dashboard accessible from outside my home network?

Several approaches work: (1) Port forward port 80 or 8080 on your router to the ESP32’s local IP — not recommended for security. (2) Use ngrok or Cloudflare Tunnel to create a secure HTTPS URL — free tier available. (3) Use MQTT to publish sensor data to a cloud broker and build the dashboard in a cloud app. Option 3 is the most scalable and secure for production use.

Why does the ESP32 web server crash after a few hours?

Common causes: (1) WebSocket clients not being cleaned up — call ws.cleanupClients() in your loop. (2) Memory leaks from creating String objects in request handlers — use const char* literals where possible. (3) Watchdog timer expiring if your loop takes too long — add vTaskDelay(1) to yield to the RTOS. Check free heap with ESP.getFreeHeap() to identify memory leaks.

Can the ESP32 web server handle file uploads?

Yes. ESPAsyncWebServer supports multipart form uploads via the onFileUpload callback. Uploaded files can be saved directly to LittleFS. This is useful for OTA firmware updates, certificate uploads, or configuration file updates through the browser interface.

Get Your ESP32 Development Boards from Zbotic

Build your ESP32 web dashboard with boards and sensors sourced from Zbotic — India’s trusted electronics component store with fast delivery and genuine components.

Shop ESP32 Boards & IoT Sensors

Tags: ESP32, ESPAsyncWebServer, IoT Dashboard, Web Server, WebSocket
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
ESP32 Modbus TCP: Connect Indu...
blog esp32 modbus tcp connect industrial plcs to iot cloud 595340
blog esp32 led strip controller ws2812b wled firmware guide 595352
ESP32 LED Strip Controller: WS...

Related posts

Svg%3E
Read more

IoT Home Insurance Sensor Kit: Leak, Smoke, and Motion

April 1, 2026 0
Table of Contents IoT and Home Insurance Water Leak Detection Smoke and Fire Detection Motion and Intrusion Sensing Building the... Continue reading
Svg%3E
Read more

IoT Pet Tracker: GPS Collar with Geofencing Alerts

April 1, 2026 0
Table of Contents Introduction and Overview Hardware Components Required GPS Module Integration with ESP32 Cloud Platform Setup Real-Time Tracking Dashboard... Continue reading
Svg%3E
Read more

IoT Aquaponics Controller: Fish and Plant Automation

April 1, 2026 0
Table of Contents The Water Monitoring Challenge in India Sensor Technologies for Water Building the Sensor Node Data Transmission and... Continue reading
Svg%3E
Read more

IoT Composting Monitor: Temperature and Moisture Tracking

April 1, 2026 0
Table of Contents Why Temperature Monitoring Matters Sensor Selection Guide Hardware Assembly and Wiring Firmware Development Cloud Data Logging Alert... Continue reading
Svg%3E
Read more

IoT Beehive Monitor: Weight, Temperature, and Humidity

April 1, 2026 0
Table of Contents Why Monitor Beehives Weight Measurement System Temperature and Humidity Sensing Building the Monitor Data Analysis for Bee... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now