Free · v2.0

Add a one-click ESP32 firmware installer to any website

A single <script> tag. One custom element. Your visitors flash ESP32, ESP8266, and ESP32-S3 devices directly from the browser — no boot button, no IDE, no drivers, no uploads. Now with serial monitor, light/dark themes, and auto-connect.

Live Demo
Two button styles shown. Click to try — the manifest contains blink firmwares for ESP32, ESP8266, S2, S3, C3.

The easiest way to let users flash your ESP firmware

ESP Flash Button is a browser-based firmware installer you embed on your website. It uses the Web Serial API to communicate with ESP32, ESP8266, and ESP32-S3 microcontrollers — no software installation, no IDE, no USB driver configuration.

Built for makers and product teams
Whether you're selling dev boards, running a tutorial blog, or distributing firmware for your project — embed the installer and let your users flash in one click.
100% private — local by design
Firmware files are fetched from your server and written directly to the device in the browser. No data ever passes through a third-party server. Zero telemetry, zero tracking.
Works everywhere on the modern web
A standard HTML web component. Deploy it on WordPress, Ghost, GitHub Pages, Cloudflare Pages, or any static site host. No build step, no npm, no framework.
More than just flashing
Built-in serial monitor, light/dark theme support, auto-connect to previously used ports, per-chip firmware auto-selection, and MD5 verification after every write.

From click to flashed firmware

The entire flash process happens in the browser. Here's what happens when a user clicks your button.

1
User clicks the button
If the user has previously authorized a serial port on this site, the component auto-connects and skips the port selection dialog. Otherwise, a modal opens showing your firmware name, supported chip variants, and a connect button.
2
Chip detection & verification
The tool connects to the device at 460800 baud (or your configured speed), identifies the chip family, reads the MAC address, detects flash size, and auto-selects the correct firmware variant from your manifest.
3
Firmware download & flash
The firmware .bin files are fetched from your server, compressed in-browser, and written to the device's flash memory with real-time progress. Every byte is verified via MD5 after writing.
4
Done! Open serial monitor (optional)
The device reboots and runs the new firmware. The success screen shows chip details, duration, and per-file MD5 hashes. Click Serial Monitor to open a live terminal — send commands, toggle DTR/RTS, timestamps, auto-scroll, and adjustable baud rate.

Two lines of code

Drop these into any HTML page. No build step, no npm, no framework.

1
Add the script tag
Load the component from Cloudflare CDN — one tag, zero dependencies.
<!-- Add this once, anywhere in your page -->
<script src="https://esp-flash-button.pages.dev/esp-flash-button.js"></script>
2
Place the button element
Add the custom element wherever you want the flash button to appear.
<esp-flash-button
  manifest="https://yoursite.com/firmware/manifest.json">
</esp-flash-button>
3
Custom button style
Use the button-style attribute to choose a predefined style, or slot="activate" to supply your own button.
<!-- Built-in styles: minimal, outline, ghost, gradient, neon -->
<esp-flash-button
  manifest="https://yoursite.com/firmware/manifest.json"
  button-style="gradient"
  label="Install My Firmware">
</esp-flash-button>

<!-- Fully custom button via slot -->
<esp-flash-button manifest="https://yoursite.com/firmware/manifest.json">
  <button slot="activate" class="my-custom-btn">
    Download Firmware
  </button>
</esp-flash-button>
4
Set theme and advanced options
Add theme, show-baud, or erase-first attributes.
<esp-flash-button
  manifest="https://yoursite.com/firmware/manifest.json"
  theme="light"
  show-baud
  erase-first
  label="Install Firmware">
</esp-flash-button>
5
Listen to flash events
React to success or failure with standard DOM events.
<script>
document.querySelector('esp-flash-button')
  .addEventListener('flash-success', (e) => {
    console.log('Flashed!', e.detail);
    // e.detail = { chip, flashSize, duration, filesCount }
  });
document.querySelector('esp-flash-button')
  .addEventListener('flash-error', (e) => {
    console.error('Failed:', e.detail);
  });
</script>

All attributes

Every attribute you can set on the <esp-flash-button> element.

AttributeDefaultDescription
manifestrequiredAbsolute URL to your firmware manifest JSON file.
label"Install Firmware"Text shown on the default flash button. Ignored when using a slotted button.
button-style"default"Button appearance. One of: default, minimal, outline, ghost, gradient, neon. See showcase below.
theme"dark"Modal color scheme. dark or light. Can also set via CSS custom properties.
baud460800Flash baud rate. For ESP8266/ESP8285, capped to 115200 automatically.
show-baudBoolean. When present, shows a baud rate dropdown (9600–921600) in the ready panel so users can adjust flash speed.
erase-firstfalseBoolean. When present, erases entire flash before writing. Users can also toggle this via a checkbox in the UI.
no-auto-connectBoolean. When present, disables auto-connect. Users will always see the "Connect Device" button and must manually select their serial port.

DOM events

EventDetailDescription
flash-success{ chip, flashSize, duration, filesCount }Fired after firmware is written and device has reset.
flash-error{ title, message }Fired if the flash process fails.

Six built-in button templates

Set button-style to one of these values. Each is rendered live below.

Default
button-style="default"
Minimal
button-style="minimal"
Outline
button-style="outline"
Ghost
button-style="ghost"
Gradient
button-style="gradient"
Neon
button-style="neon"

Dark, light, or your own colors

Set theme="light" for a light modal, or override individual CSS custom properties.

Dark (default)
<esp-flash-button>
Light
<esp-flash-button theme="light">
Custom colors via CSS variables
Define any subset of these variables on esp-flash-button or any ancestor element. The component inherits them automatically.
esp-flash-button {
  --efb-accent: #2266ff;      /* Primary accent (default red) */
  --efb-bg-surface: #1a1a2e; /* Modal background */
  --efb-bg-card: #222244;     /* Card backgrounds */
  --efb-text-primary: #eee;   /* Primary text */
  --efb-success: #44dd88;     /* Success indicators */
  --efb-warning: #ffaa00;     /* Warning indicators */
  --efb-font-mono: 'Fira Code'; /* Monospace font */
}
All available CSS variables with their defaults: --efb-bg-base, --efb-bg-surface, --efb-bg-card, --efb-bg-status, --efb-bg-hover, --efb-border, --efb-border-subtle, --efb-border-card, --efb-text-primary, --efb-text-secondary, --efb-text-muted, --efb-text-dim, --efb-text-faint, --efb-accent, --efb-accent-hover, --efb-accent-dark, --efb-accent-darker, --efb-accent-light, --efb-accent-bright, --efb-success, --efb-success-dark, --efb-success-darker, --efb-success-hover, --efb-warning, --efb-font, --efb-font-mono, --efb-radius-sm, --efb-radius-md, --efb-radius-lg, --efb-radius-btn.

No port selection on repeat visits

If a user has previously authorized a serial port on your site, the component reconnects automatically — no browser dialog needed.

How it works
When the user opens the flash modal, the component calls navigator.serial.getPorts(). If a previously authorized port is found, it reconnects automatically and shows a "Flash Firmware" button directly — the user never sees a port selection dialog.
No configuration needed
Auto-connect works automatically with no extra attributes. It's built into every <esp-flash-button>. The first time, users see the standard port picker; on subsequent visits, they connect instantly. When auto-connected, a Change Port button lets users pick a different device. Developers can disable auto-connect entirely with the no-auto-connect attribute.

Built-in real-time serial console

After flashing, users can open a full-featured serial monitor directly in the browser — no separate terminal app needed.

Real-time read & write
Full-duplex serial communication with configurable baud rate (9600–921600). Uses the Web Serial API ReadableStream for zero-latency streaming.
Line endings & timestamps
Choose LF, CRLF, CR, or None for sent commands. Toggle optional timestamps on each line. Auto-scroll keeps the latest output visible.
DTR/RTS reset
A "DTR/RST" button toggles the serial control signals, performing a hardware reset of the connected ESP device — just like pressing the RST button.
2000-line rolling buffer
Keeps the last 2000 lines in memory. Clear button resets the output. The monitor integrates seamlessly into the flash dialog.
How to open the serial monitor
After a successful flash, the success screen includes a Serial Monitor button. Click it to request a separate serial port and open the terminal. The monitor is also accessible from the footer after connection.

Your firmware manifest

A simple JSON file that tells the component what firmware to flash and for which chips. Host it on your server alongside your .bin files.

Your server must send CORS headers so the browser can fetch the manifest and firmware files cross-origin. Add Access-Control-Allow-Origin: * to your server responses.
Single merged .bin (simplest — address 0x0)
{
  "name": "My ESP32 Project",
  "version": "1.0.0",
  "builds": [
    {
      "chipFamily": "ESP32",
      "parts": [
        { "path": "firmware.bin", "offset": 0 }
      ]
    }
  ]
}
Multi-chip with all features
{
  "name": "My Firmware",
  "version": "2.1.0",
  "new_install_prompt_erase": true,
  "funding_url": "https://ko-fi.com/yourproject",
  "builds": [
    {
      "chipFamily": "ESP32",
      "parts": [
        { "path": "bootloader.bin",   "offset": 4096  },
        { "path": "partitions.bin",   "offset": 32768 },
        { "path": "boot_app0.bin",   "offset": 57344 },
        { "path": "firmware.bin",    "offset": 65536 }
      ]
    },
    {
      "chipFamily": "ESP32-S3",
      "parts": [
        { "path": "firmware-s3.bin", "offset": 0     }
      ]
    },
    {
      "chipFamily": "ESP8266",
      "parts": [
        { "path": "firmware-8266.bin", "offset": 0    }
      ]
    }
  ]
}
new_install_prompt_erase
When set to true, the erase checkbox is checked by default and a yellow info banner explains that flash memory will be erased. Users can uncheck to skip erase.
funding_url
When set, a small "Support" link appears in the modal footer. Useful for open-source projects to receive donations from users who appreciate the firmware.

Everything you get

A comprehensive feature set for embedding firmware installation on any website.

No BOOT button hold required
The SKR engine handles ROM bootloader entry via DTR/RTS automatically. Most boards flash without holding any buttons.
Chip + MAC + flash size auto-detection
Probes chip type, MAC address, and flash size on connect. Auto-selects the correct firmware variant from your manifest.
Built-in serial monitor
Full-duplex serial terminal with configurable baud, line endings, timestamps, auto-scroll, and DTR/RTS reset. Opens after flash success.
Light / dark themes + custom colors
Set theme="light" or override 25+ CSS custom properties for a fully custom look.
Auto-connect on repeat visits
Uses navigator.serial.getPorts() to reconnect to previously authorized ports automatically.
Fast flash speed (460800 baud)
Default 460800 baud with compression. ESP8266/ESP8285 limited to 115200 for reliability. Optionally expose baud selection with show-baud.
6 button templates
Choose from default, minimal, outline, ghost, gradient, or neon. Or supply your own button via slot="activate".
100% local — private by design
All flashing happens locally in the browser. Firmware and device data never touch any server. Zero telemetry.

ESP Flash Button vs ESP Web Tools

A detailed feature comparison. ESP Flash Button is the more capable, faster, and better-looking alternative.

ESP Flash Button
Auto bootloader entry — no BOOT button hold
Chip + MAC + flash size auto-detection
Fast flash speed: 460800 baud with compression
MD5 verification after every write
Built-in serial monitor (full-duplex)
Light/dark themes + custom CSS colors
6 button templates + custom slot
Auto-connect to previously authorized ports
DOM events (flash-success / flash-error)
Same manifest format (fully compatible)
Modern dark-mode UI with animated feedback
ESP Web Tools
Requires holding BOOT button on most boards
Basic chip family detection
Slower default baud rate
No MD5 verification
No serial monitor
No theme support
Single button style
No auto-connect
DOM events
Improv Wi-Fi standard support
Dated, light-themed UI

Supported chips & boards

ESP Flash Button supports all ESP32-family chips supported by esptool-js. Any board with a USB-to-serial converter works.

ESP32
ESP32-S2
ESP32-S3
ESP32-C3
ESP32-C6
ESP32-H2
ESP8266
ESP8285
Browser requirement: Chrome 89+, Edge 89+, or Opera 76+ (desktop). Web Serial API is not available in Firefox or Safari.
USB-serial chips: CP2102, CP2104, CH340, CH341, FTDI FT232R, and any CDC-ACM serial adapter.

Frequently asked questions

What is ESP Flash Button?
ESP Flash Button is a free web component that adds a one-click firmware installer to any website. It uses the Web Serial API to flash ESP32, ESP8266, and ESP32-S3 microcontrollers directly from the browser. It's built by SKR Electronics Lab and powered by Espressif's esptool-js.
How is this different from ESP Web Tools?
ESP Flash Button is built on the SKR Flasher engine which automatically handles ROM bootloader entry — most boards flash without holding any buttons. It also features a built-in serial monitor, light/dark theme support, auto-connect to previously authorized ports, 6 button templates, and MD5 verification after every write with an animated modern UI.
Which browsers are supported?
Google Chrome 89+, Microsoft Edge 89+, and Opera 76+ on desktop. The Web Serial API is required, which Firefox and Safari do not currently support. Mobile browsers are not supported.
Do I need to hold the BOOT button?
In most cases, no. The SKR Flasher engine manages bootloader entry automatically via DTR/RTS serial handshake lines. Simply plug in your board, click Connect, and the tool handles the rest. Some boards with non-standard USB-serial chips may still need manual button intervention.
Is my firmware uploaded to your servers?
No. Everything happens locally in your browser. Firmware files are fetched directly from your own server and written to the device via the Web Serial API. No data passes through any third-party server. Zero telemetry.
What's the flash speed?
Default flash speed is 460800 baud with hardware compression enabled. A typical 2 MB firmware completes in under 20 seconds. You can reduce baud rate via the baud attribute, or expose the baud selector to users with show-baud.
What is the serial monitor and how do I use it?
After a successful flash, the success screen includes a "Serial Monitor" button. Click it, select your ESP device's serial port, and you get a full-duplex terminal: read output, send commands, toggle DTR/RTS reset, adjust baud rate, choose line endings, add timestamps, and toggle auto-scroll. It's a full serial console in the browser.
Can I use my own button styling?
Yes. Use the button-style attribute to pick from 6 built-in templates (default, minimal, outline, ghost, gradient, neon), or use slot="activate" to supply your own custom button element.
How do I customize the colors?
Set the theme attribute to "light" for a light mode, or override individual CSS custom properties like --efb-accent, --efb-bg-surface, and --efb-text-primary on the esp-flash-button element.
Does auto-connect work across page reloads?
Yes. Once a user authorizes a serial port via the browser dialog, the browser remembers the permission. On subsequent visits (or page reloads), navigator.serial.getPorts() returns the previously authorized port and the component reconnects automatically.

CORS configuration

Your manifest and .bin files must allow cross-origin requests from the page embedding the button. Add these headers to your server:

# Apache (.htaccess)
Header set Access-Control-Allow-Origin "*"

# Nginx
add_header Access-Control-Allow-Origin *;

# Cloudflare Pages (_headers)
/firmware/*
  Access-Control-Allow-Origin: *

# Express / Node.js
app.use('/firmware', (req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  next();
});