esp32 intermediate 30 min

ESP32: set up a captive portal for Wi-Fi configuration

Make the ESP32 broadcast its own Wi-Fi network and serve a configuration page. The right pattern for projects that need Wi-Fi credentials but have no keyboard.

Code available for: ESP32 Arduino
Published Aug 25, 2026

The captive portal is the pattern where an ESP32 broadcasts its own Wi-Fi network (like a router does), and when you connect to it, your phone or laptop automatically opens a configuration page. You enter your home Wi-Fi credentials, the ESP32 saves them, and restarts connected to your network.

This is how every Wi-Fi-enabled smart device handles its first-time setup. Bulbs, plugs, sensors: they all start in AP mode, you connect, you configure.

This is ESP32-specific (Wi-Fi captive portals are not a feature of the Uno, Pi, or Pico).

What you need

  • ESP32 dev board
  • A phone or laptop with Wi-Fi

Install libraries

Sketch >> Include Library >> Manage Libraries >> search for WiFiManager by tzapu. Install it.

WiFiManager is the standard library for ESP32 captive portals. It does all the AP setup, DNS handling, and config saving for you.

The code

#include <WiFiManager.h>

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting WiFiManager");

  WiFiManager wm;

  // Reset settings (uncomment for first-time setup)
  // wm.resetSettings();

  bool connected = wm.autoConnect("ESP32-Setup");

  if (!connected) {
    Serial.println("Failed to connect, restarting");
    ESP.restart();
  }

  Serial.println("Connected to Wi-Fi");
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // Your main code here
}

Upload and run. The ESP32 will:

  1. If already configured: connect to the saved Wi-Fi network.
  2. If not configured: create a Wi-Fi network called “ESP32-Setup”.
  3. You connect to that network with your phone.
  4. Your phone’s captive portal detection opens a configuration page (some phones open it automatically; others need you to tap a “Sign In” or “Configure Wi-Fi” notification).
  5. You select your home network from the list and enter the password.
  6. The ESP32 saves the credentials and restarts.
  7. On restart, the ESP32 connects to your home network.

What the configuration page looks like

The WiFiManager library serves a configuration page with:

  • A list of visible Wi-Fi networks
  • A password field
  • A “Save” button
  • Optional: custom parameters (MQTT broker, sensor names, etc.)

You can customize the page with HTML, add a logo, or add custom parameters. The library docs at https://github.com/tzapu/WiFiManager cover this.

Adding custom parameters

For projects that need more than Wi-Fi credentials (e.g. an MQTT broker URL), add custom parameters:

WiFiManager wm;
WiFiManagerParameter mqttServer("mqtt", "MQTT Server", "192.168.1.50", 40);
WiFiManagerParameter mqttPort("port", "MQTT Port", "1883", 6);

wm.addParameter(&mqttServer);
wm.addParameter(&mqttPort);

bool connected = wm.autoConnect("ESP32-Sensor");

if (connected) {
  String server = mqttServer.getValue();
  String port = mqttPort.getValue();
  // Save to EEPROM or use directly
  preferences.begin("config", false);
  preferences.putString("mqttServer", server);
  preferences.putInt("mqttPort", port.toInt());
  preferences.end();
}

The custom parameters are saved alongside the Wi-Fi credentials and restored on reboot.

The timeout

autoConnect() blocks until either the user configures Wi-Fi or a timeout expires. Default is 3 minutes. Set your own:

wm.setConfigPortalTimeout(180);   // 3 minutes in seconds

bool connected = wm.autoConnect("ESP32-Setup");
if (!connected) {
  Serial.println("No config, going to sleep");
  esp_deep_sleep_start();
}

After timeout, the ESP32 restarts (or you can do something else, like go into a configuration mode).

The reset button pattern

If you want to clear saved credentials (so the user can reconfigure), hold a button at boot:

#include <WiFiManager.h>

const int RESET_BTN_PIN = 4;

void setup() {
  pinMode(RESET_BTN_PIN, INPUT_PULLUP);
  if (digitalRead(RESET_BTN_PIN) == LOW) {
    WiFiManager wm;
    wm.resetSettings();
    Serial.println("Settings reset, restart to enter config mode");
    while (1);   // wait for user to release button
  }
  // ... normal setup ...
}

Hold the button, power on, wait for the reset message, release, restart. The ESP32 will start in AP mode for reconfiguration.

What you learned

  • WiFiManager is the standard library for ESP32 captive portals.
  • The ESP32 starts in AP mode if not configured, or connects to the saved network if configured.
  • Custom parameters can be added for MQTT brokers, sensor names, etc.
  • A reset button is the standard way to clear saved credentials.

When something breaks

  • Phone does not auto-open the config page. Some phones do not trigger captive portal detection. Open 192.168.4.1 in a browser manually.
  • Saved credentials do not stick. Some WiFiManager versions have bugs. Update the library.
  • ESP32 keeps restarting. The configuration is invalid. Try wm.resetSettings() and reconfigure.
  • “Failed to connect” after timeout. Increase the timeout or check the Wi-Fi credentials.

What to build next

  • The Wi-Fi connect tutorial covers the basic Wi-Fi setup pattern.
  • The ESP32 MQTT tutorial combines with the captive portal for cloud-connected devices.
  • The book ESP32 Smart Home covers production-ready configuration flows with OTA updates.