Pas besoin de npm, de React ni d'un bundler pour parler MQTT depuis une page web. MQTT.js 5 fournit un bundle prêt pour le navigateur : ajoutez une balise <script>, appelez mqtt.connect('wss://…'), et la page publie et s'abonne en WebSocket sécurisé. Ce guide construit un client complet dans un seul fichier, que vous pouvez ouvrir depuis le disque, déposer sur n'importe quel hébergement statique ou coller dans un outil interne.
Pourquoi les navigateurs ont besoin des WebSockets
Les navigateurs ne peuvent pas ouvrir de sockets TCP bruts : mqtt://host:1883 et mqtts://host:8883 sont donc hors de portée d'une page web. Les brokers résolvent ce problème avec un listener WebSocket : les mêmes paquets MQTT voyagent dans des trames WebSocket. Pour broker.connectmq.com, les endpoints sont :
| URL | Usage |
|---|---|
ws://broker.connectmq.com:8083/mqtt | WebSocket non chiffré, uniquement pour les pages servies en http:// ou file:// |
wss://broker.connectmq.com:8084/mqtt | WebSocket sécurisé (TLS), fonctionne depuis toute page ; à utiliser par défaut |
Le chemin /mqtt compte : se connecter au bon port avec le mauvais chemin échoue généralement pendant l'upgrade HTTP (voir erreur 404 sur le chemin WebSocket). MQTT sur WebSockets explique ce transport en détail.
La page complète
Enregistrez ceci sous index.html. La page fixe une version exacte de MQTT.js depuis le CDN, qui expose un objet global mqtt.
<!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>Ouvrez le fichier, tapez un message et cliquez sur Publish : la page est abonnée à son propre topic aléatoire, le message revient donc par le broker et s'affiche dans le log. Chaque onglet a son propre topic et son propre client ID, deux onglets ouverts ne se gênent donc pas. Pour observer le trafic de l'extérieur, ouvrez le client MQTT en ligne, abonnez-vous à testmqtt/browser-demo/# et publiez d'un côté ou de l'autre.
Variante en module ES
Si vous préférez les modules, MQTT.js publie aussi un build ESM. Aucune variable globale n'est créée, vous l'importez donc :
<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>Les scripts module sont différés automatiquement et ne polluent pas window. Certains navigateurs bloquent les scripts module sur les pages ouvertes en file:// : servez donc le dossier avec un serveur web local :
python3 -m http.server 8000
# puis ouvrez http://localhost:8000/Les options qui comptent dans un navigateur
| Option | Recommandé | Pourquoi |
|---|---|---|
clientId | Aléatoire par onglet | Deux onglets avec le même ID s'éjectent mutuellement en boucle |
protocolVersion | 5 (ou 4 pour 3.1.1) | MQTT 5 fournit des reason codes dans les erreurs, ce qui facilite le débogage |
keepalive | 30–60 s | Les portables se mettent en veille et le Wi-Fi change ; un keep-alive court détecte plus vite les sockets morts |
reconnectPeriod | 2 000–5 000 ms | 0 désactive la reconnexion automatique ; des valeurs trop petites martèlent le broker |
connectTimeout | 10 000 ms | Échouer vite et afficher un état à l'utilisateur plutôt que de charger indéfiniment |
clean | true | Un onglet de navigateur a rarement besoin d'une session persistante |
Générez des ID avec un préfixe reconnaissable dans les logs du broker, ou utilisez le générateur de client ID. Si vous avez besoin de la même configuration dans un autre langage, le générateur de code MQTT produit des extraits équivalents.
Identifiants dans une page statique
Tout ce qui figure dans un fichier HTML est public : n'importe qui peut afficher le code source et copier username et password. Traitez les identifiants côté navigateur en conséquence :
- Créez un utilisateur de broker dédié à la page et limitez-le par ACL aux seuls topics dont elle a besoin. Un dashboard n'a généralement besoin que d'un accès en lecture à
.../telemetry/#. - Ne réutilisez jamais dans le navigateur un compte d'appareil, de backend ou d'administration.
- Pour les utilisateurs connectés, laissez votre backend émettre des identifiants par utilisateur ou à courte durée de vie après authentification, et passez-les à
mqtt.connect.
L'authentification MQTT par WebSocket dans le navigateur détaille ces approches.
Déboguer la connexion
Ouvrez les DevTools (F12) et regardez à deux endroits :
- Console. Les erreurs de l'événement
erroret les messages WebSocket du navigateur lui-même s'y affichent. - Network → WS. Sélectionnez la connexion pour voir l'upgrade HTTP (statut
101 Switching Protocolsen cas de succès) et les trames MQTT binaires dans l'onglet Messages.
| Message dans la console | Cause probable | Correctif |
|---|---|---|
Mixed Content: The page at 'https://…' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://…' | ws:// utilisé depuis une page HTTPS | Utilisez wss://…:8084/mqtt |
WebSocket connection to 'wss://…' failed | Mauvais port ou chemin, firewall, problème TLS | Vérifiez le port 8084 et le chemin /mqtt ; voir la connexion WebSocket échoue |
connack timeout | Le WebSocket s'est ouvert mais le CONNACK n'est pas arrivé à temps | Broker surchargé ou proxy qui met en tampon ; augmentez connectTimeout et réessayez |
Connection refused: Not authorized / Bad User Name or Password | Identifiants absents ou incorrects | Vérifiez le nom d'utilisateur, le mot de passe et les ACL de l'utilisateur |
| L'état alterne entre connecté et reconnexion | Client ID en double dans un autre onglet ou appareil | Rendez clientId unique par onglet |
L'outil de recherche de reason codes traduit les codes numériques renvoyés par les brokers MQTT 5. Pour mettre complètement votre page hors de cause, testez la même URL dans le client en ligne : s'il s'y connecte, le problème vient de votre code, pas du broker ni du réseau.
Voir le topic de la page démo dans le client en ligne
Et ensuite
La page ci-dessus est un client complet. Les étapes suivantes classiques sont une interface de chat (un topic par salon, présence via Last Will), un graphique en direct alimenté par la télémétrie de capteurs ou un panneau de contrôle qui publie des commandes. Quand le code dépasse quelques centaines de lignes, passer au paquet npm et à un bundler est simple : l'API mqtt.connect est identique, c'est d'ailleurs pourquoi le guide MQTT.js s'applique tel quel.
Une balise script, une URL wss:// et quelques gestionnaires d'événements : c'est tout ce dont un navigateur a besoin pour parler MQTT. Fixez la version de la bibliothèque, donnez à chaque onglet son propre client ID, n'envoyez au navigateur qu'un compte restreint et vérifiez chaque modification dans les DevTools et le client en ligne avant de déployer.
Questions fréquentes
Un navigateur peut-il se connecter à MQTT sur le port 1883 ou 8883 ?
Non. Les navigateurs ne peuvent pas ouvrir de sockets TCP bruts : une page web ne peut joindre un broker MQTT que via un listener WebSocket. Utilisez wss:// (port 8084 avec le chemin /mqtt sur broker.connectmq.com) depuis toute page servie en HTTPS.
Est-il sûr de mettre des identifiants MQTT dans une page HTML statique ?
Tout ce qui se trouve dans la page est lisible par chaque visiteur. Utilisez un utilisateur de broker dédié dont l'ACL n'autorise que les topics nécessaires à cette page (souvent en lecture seule), ou laissez votre backend fournir des identifiants à courte durée de vie. N'envoyez jamais un compte administrateur ou un compte d'appareil au navigateur.
Pourquoi ma page fonctionne en local mais échoue une fois déployée ?
Le plus souvent à cause du contenu mixte. Une page servie en https:// ne peut pas ouvrir une connexion ws:// non sécurisée, le navigateur la bloque donc. Passez l'URL en wss:// sur le port WebSocket TLS et vérifiez le chemin.


