Du brauchst weder npm noch React noch einen Bundler, um aus einer Webseite heraus MQTT zu sprechen. MQTT.js 5 bringt ein fertiges Browser-Bundle mit: ein <script>-Tag einfügen, mqtt.connect('wss://…') aufrufen, und die Seite publisht und abonniert über sichere WebSockets. Dieser Guide baut einen vollständigen Client in einer einzigen Datei, die du direkt von der Festplatte öffnen, auf jeden statischen Host legen oder in ein internes Tool einfügen kannst.
Warum Browser WebSockets brauchen
Browser können keine rohen TCP-Sockets öffnen, deshalb sind mqtt://host:1883 und mqtts://host:8883 für eine Webseite unerreichbar. Broker lösen das mit einem WebSocket-Listener: Dieselben MQTT-Pakete reisen in WebSocket-Frames. Für broker.connectmq.com sind die Endpoints:
| URL | Einsatz |
|---|---|
ws://broker.connectmq.com:8083/mqtt | Unverschlüsselter WebSocket, nur für Seiten über http:// oder file:// |
wss://broker.connectmq.com:8084/mqtt | Sicherer WebSocket (TLS), funktioniert von jeder Seite; standardmäßig verwenden |
Der Pfad /mqtt ist wichtig: Wer den richtigen Port mit dem falschen Pfad anspricht, scheitert meist schon beim HTTP-Upgrade (siehe WebSocket-Pfad 404). MQTT über WebSockets erklärt den Transport im Detail.
Die komplette Seite
Speichere das als index.html. Die Seite pinnt eine exakte MQTT.js-Version vom CDN, die ein globales mqtt-Objekt bereitstellt.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MQTT browser client</title>
<script src="https://unpkg.com/mqtt@5.10.1/dist/mqtt.min.js"></script>
<style>
body { font: 15px/1.5 system-ui, sans-serif; max-width: 640px; margin: 2rem auto; padding: 0 1rem; }
#log { background: #111; color: #9f9; padding: .75rem; height: 260px; overflow: auto; font-family: monospace; }
input, button { font: inherit; padding: .4rem .6rem; }
</style>
</head>
<body>
<h1>MQTT over WSS</h1>
<p>Status: <strong id="status">connecting…</strong></p>
<form id="pub">
<input id="msg" placeholder="Message" required>
<button>Publish</button>
</form>
<pre id="log"></pre>
<script>
const URL = 'wss://broker.connectmq.com:8084/mqtt';
const TOPIC = 'testmqtt/browser-demo/' + Math.random().toString(16).slice(2, 8);
const $ = (id) => document.getElementById(id);
const log = (line) => {
$('log').textContent += new Date().toLocaleTimeString() + ' ' + line + '\n';
$('log').scrollTop = $('log').scrollHeight;
};
const client = mqtt.connect(URL, {
clientId: 'web-' + Math.random().toString(16).slice(2, 10),
// username: 'username', password: 'password', // see "Credentials" below
protocolVersion: 5,
clean: true,
keepalive: 30,
connectTimeout: 10_000,
reconnectPeriod: 2_000,
});
client.on('connect', () => {
$('status').textContent = 'connected';
client.subscribe(TOPIC, { qos: 1 }, (err) => {
log(err ? 'subscribe failed: ' + err.message : 'subscribed to ' + TOPIC);
});
});
client.on('message', (topic, payload) => {
log(topic + ' ' + payload.toString());
});
client.on('reconnect', () => { $('status').textContent = 'reconnecting…'; });
client.on('offline', () => { $('status').textContent = 'offline'; });
client.on('error', (err) => log('error: ' + err.message));
$('pub').addEventListener('submit', (e) => {
e.preventDefault();
client.publish(TOPIC, $('msg').value, { qos: 1 });
$('msg').value = '';
});
window.addEventListener('pagehide', () => client.end());
</script>
</body>
</html>Öffne die Datei, tippe eine Nachricht und klick auf Publish: Die Seite abonniert ihr eigenes zufälliges Topic, also kommt die Nachricht über den Broker zurück und erscheint im Log. Jeder Tab bekommt ein eigenes Topic und eine eigene Client-ID, zwei offene Tabs stören sich also nicht. Um den Traffic von außen zu sehen, öffne den Online-MQTT-Client, abonniere testmqtt/browser-demo/# und publishe von einer der beiden Seiten.
ES-Modul-Variante
Wenn du Module bevorzugst: MQTT.js veröffentlicht auch einen ESM-Build. Es wird kein Global angelegt, du importierst ihn also:
<script type="module">
import mqtt from 'https://unpkg.com/mqtt@5.10.1/dist/mqtt.esm.js';
const client = mqtt.connect('wss://broker.connectmq.com:8084/mqtt', { protocolVersion: 5 });
client.on('connect', () => client.publish('testmqtt/browser-demo/esm', 'hello from a module'));
</script>Modul-Scripts werden automatisch verzögert ausgeführt und legen keine Variablen in window ab. Manche Browser blockieren Modul-Scripts auf Seiten, die über file:// geöffnet wurden. Liefere den Ordner deshalb über einen lokalen Webserver aus:
python3 -m http.server 8000
# dann http://localhost:8000/ öffnenOptionen, die im Browser zählen
| Option | Empfehlung | Warum |
|---|---|---|
clientId | Zufällig pro Tab | Zwei Tabs mit derselben ID werfen sich gegenseitig in einer Schleife raus |
protocolVersion | 5 (oder 4 für 3.1.1) | MQTT 5 liefert Reason Codes in Fehlern, das erleichtert das Debugging |
keepalive | 30–60 s | Laptops gehen in den Ruhezustand und WLANs wechseln; ein kurzes Keep-Alive erkennt tote Sockets früher |
reconnectPeriod | 2.000–5.000 ms | 0 schaltet Auto-Reconnect ab; sehr kleine Werte hämmern auf den Broker ein |
connectTimeout | 10.000 ms | Schnell scheitern und dem Nutzer einen Status zeigen, statt endlos zu laden |
clean | true | Ein Browser-Tab braucht selten eine persistente Session |
Erzeuge IDs mit einem Präfix, das du in den Broker-Logs wiedererkennst, oder nutze den Client-ID-Generator. Brauchst du dasselbe Setup in einer anderen Sprache, liefert der MQTT-Codegenerator entsprechende Snippets.
Zugangsdaten in einer statischen Seite
Alles in einer HTML-Datei ist öffentlich: Jeder kann sich den Quelltext ansehen und username und password kopieren. Behandle Browser-Zugangsdaten entsprechend:
- Leg einen eigenen Broker-Benutzer für die Seite an und beschränke ihn per ACL auf genau die Topics, die sie braucht. Ein Dashboard braucht meist nur Lesezugriff auf
.../telemetry/#. - Verwende im Browser niemals einen Geräte-, Backend- oder Admin-Account wieder.
- Für eingeloggte Nutzer lässt du dein Backend nach der Authentifizierung benutzerbezogene oder kurzlebige Zugangsdaten ausstellen und übergibst sie an
mqtt.connect.
MQTT-WebSocket-Authentifizierung im Browser geht diese Muster im Detail durch.
Die Verbindung debuggen
Öffne die DevTools (F12) und schau an zwei Stellen nach:
- Console. Hier erscheinen Fehler aus dem
error-Event und die WebSocket-Meldungen des Browsers selbst. - Network → WS. Wähl die Verbindung aus, um das HTTP-Upgrade (Status
101 Switching Protocolsbei Erfolg) und die binären MQTT-Frames im Tab Messages zu sehen.
| Meldung in der Konsole | Wahrscheinliche Ursache | Lösung |
|---|---|---|
Mixed Content: The page at 'https://…' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://…' | ws:// auf einer HTTPS-Seite | wss://…:8084/mqtt verwenden |
WebSocket connection to 'wss://…' failed | Falscher Port oder Pfad, Firewall, TLS-Problem | Port 8084 und Pfad /mqtt prüfen; siehe WebSocket-Verbindung schlägt fehl |
connack timeout | WebSocket offen, aber kein CONNACK rechtzeitig | Broker überlastet oder ein Proxy puffert; connectTimeout erhöhen und erneut versuchen |
Connection refused: Not authorized / Bad User Name or Password | Fehlende oder falsche Zugangsdaten | Benutzername, Passwort und die ACLs des Benutzers prüfen |
| Status springt zwischen verbunden und reconnecting | Doppelte Client-ID in einem anderen Tab oder Gerät | clientId pro Tab eindeutig machen |
Das Reason-Code-Nachschlagewerk übersetzt die numerischen Codes, die MQTT-5-Broker zurückgeben. Um deine Seite komplett auszuschließen, probier dieselbe URL im Online-Client: Verbindet er sich dort, liegt das Problem in deinem Code, nicht am Broker oder Netzwerk.
Topic der Demo-Seite im Online-Client ansehen
Wie es weitergeht
Die Seite oben ist ein vollständiger Client. Typische nächste Schritte sind eine Chat-Oberfläche (ein Topic pro Raum, Presence über Last Will), ein Live-Chart mit Sensor-Telemetrie oder ein Bedienpanel, das Befehle publisht. Wenn der Code über ein paar hundert Zeilen wächst, ist der Umstieg auf das npm-Paket und einen Bundler einfach: Die mqtt.connect-API ist identisch, weshalb der MQTT.js-Guide unverändert gilt.
Ein Script-Tag, eine wss://-URL und ein paar Event-Handler sind alles, was ein Browser für MQTT braucht. Pinne die Bibliotheksversion, gib jedem Tab eine eigene Client-ID, liefere nur einen eingeschränkten Account an den Browser aus und prüfe jede Änderung in den DevTools und im Online-Client, bevor du deployst.
Häufig gestellte Fragen
Kann sich ein Browser auf Port 1883 oder 8883 mit MQTT verbinden?
Nein. Browser können keine rohen TCP-Sockets öffnen, deshalb erreicht eine Webseite einen MQTT-Broker nur über einen WebSocket-Listener. Nutze wss:// (Port 8084 mit dem Pfad /mqtt bei broker.connectmq.com) von jeder per HTTPS ausgelieferten Seite.
Ist es sicher, MQTT-Zugangsdaten in eine statische HTML-Seite zu schreiben?
Alles in der Seite kann jeder Besucher lesen. Nutze einen eigenen Broker-Benutzer, dessen ACL nur die Topics erlaubt, die die Seite braucht (oft nur lesend), oder lass dein Backend kurzlebige Zugangsdaten ausgeben. Liefere niemals einen Admin- oder Geräte-Account an den Browser aus.
Warum funktioniert meine Seite lokal, aber nicht nach dem Deployment?
Meistens wegen Mixed Content. Eine über https:// ausgelieferte Seite darf keine unsichere ws://-Verbindung öffnen, also blockiert der Browser sie. Stell die URL auf wss:// am TLS-WebSocket-Port um und prüfe den Pfad.


