Mise à jour du 15 octobre 2026
Odoo 20 est sorti depuis la publication de cet article. L'audit ci-dessous porte sur la 19.4 et n'a pas encore été refait sur la 20 : les chiffres valent pour la 19.4. La méthode décrite en fin d'article permet de refaire chaque test sur une version plus récente.
Audit mesuré sur saas~19.4+e le 25 juillet 2026. Bundle analysé, tests runtime, captures. Chaque chiffre est traçable.
Depuis quelques mois, une phrase revient dans les réunions d'avant-projet : « Odoo va faire l'offline, vos applications ne serviront plus ». Elle mérite mieux qu'une réponse commerciale. On a donc testé.
Nous sommes intégrateur et partenaire Odoo : nous partons des processus de nos clients pour configurer Odoo, et nous ajoutons une application terrain quand leurs équipes travaillent sans réseau. Savoir où s'arrête le standard fait partie du travail.
Odoo 19.4 embarque un vrai moteur hors connexion. C'est nouveau et il faut le reconnaître. Ce moteur ne couvre pas le travail de terrain, pour six raisons mesurables qui ne relèvent pas du bug.
Ce qui existe, et qu'il faut arrêter de nier
Le service @web/core/offline/offline_service est enregistré par défaut dans la 19.4, actif sans configuration.
| Brique | État | Détail |
|---|---|---|
| Détection de perte réseau | ConnectionLostError, événements online/offline, polling à backoff exponentiel | |
| Stockage local | IndexedDB, valeurs chiffrées en AES-GCM | |
| File d'écritures | table orm-to-sync, rejeu séquentiel, verrou navigator.locks | |
| Indicateur utilisateur | systray « Working offline », « Syncing », « Sync issues » | |
| Édition et sauvegarde hors connexion | testé, web_save mis en file puis rejoué |
Vous perdez le réseau dix minutes, votre onglet reste ouvert, vous corrigez deux champs sur une fiche déjà affichée : ça marche, et ça rend service à un utilisateur de bureau.
L'offline-first commence ailleurs, et l'écart se mesure sur six points.
Les 6 points de rupture
1. Quatre méthodes ORM seulement sont rejouables
La liste est exhaustive, extraite de l'énumération STATUS du systray et du modèle record.js :
web_save → créé / modifié
unlink → supprimé
action_archive → archivé
action_unarchive → désarchivé
Aucun appel de méthode métier n'est mis en file d'attente. C'est la cause du point suivant.
2. Tout bouton métier est désactivé hors connexion
Le mécanisme fonctionne en liste blanche : button:not([data-available-offline]) est grisé. Tout ce qui n'est pas explicitement marqué comme sûr hors connexion devient inactif.
On a compté les occurrences du marqueur data-available-offline dans l'intégralité du bundle 19.4 : 112 occurrences, toutes dans le chrome web générique (pagination, barre de navigation, dialogues, sélecteur de date, recherche) et dans Discuss. Modules métier : zéro. Ni stock, ni timesheet, ni projet, ni qualité, ni maintenance, ni vente.
23 rouges = boutons désactivés hors connexion, dont Valider, Signer, Imprimer, Code-barres, Mettre en colis et Joindre un fichier.
Traduction terrain : hors connexion, un magasinier peut modifier un champ. Il ne peut pas valider son opération.
3. Photos, signatures et pièces jointes : aucun support
Recherche d'occurrences du mot offline et de ConnectionLostError dans les modules concernés :
| Module | offline | ConnectionLostError |
|---|---|---|
file_upload_service | 0 | 0 |
name_and_signature | 0 | 0 |
image_field | 0 | 0 |
binary_field | 0 | 0 |
file_input | 0 | 0 |
Pas de photo d'intervention, pas de signature client, pas de pièce jointe. Sur un rapport d'intervention, ce sont les éléments qui font foi devant un client ou un assureur.
4. Hors connexion, vous n'avez accès qu'à ce que vous avez déjà ouvert
La fonction _populateVisited() reconstruit la surface disponible à partir des écrans réellement ouverts pendant la session en ligne. Il n'existe aucun mécanisme pour provisionner un jeu de données avant de partir.
| Action hors connexion | État | Résultat |
|---|---|---|
| Rouvrir une fiche déjà consultée | fonctionne | |
| Ouvrir une fiche de la liste jamais consultée | rien ne se passe, ni formulaire, ni erreur, ni notification | |
| Ouvrir une action jamais chargée | ConnectionLostError | |
| Appliquer un filtre différent de celui utilisé en ligne | « There is no data to display offline for the given filters » |
Le deuxième cas est le plus problématique. L'échec est silencieux. L'utilisateur clique, rien ne bouge, il ne comprend pas pourquoi son application ne réagit pas. En formation, c'est ce comportement qui produit le plus d'appels au support.
5. L'application ne redémarre pas hors connexion
Test : application en état hors connexion, rechargement de la page.
GET /odoo/action-845 200 ← coquille HTML du service worker
GET /web/assets/…/web.assets_web.min.js 200 ← bundle depuis le cache HTTP
GET /web/webclient/load_menus ERR_INTERNET_DISCONNECTED
GET /web/webclient/translations?hash=… ERR_INTERNET_DISCONNECTED ← bloquant
TypeError: Failed to fetch
at LocalizationPlugin.fetchTranslations
at async startServices
at async startWebClient
Le chargement des traductions est une dépendance dure et non mise en cache du démarrage des services. Résultat mesuré : document.body.innerText vide. Page blanche.
Les écritures en attente survivent dans IndexedDB, on l'a vérifié. Mais elles restent inaccessibles jusqu'au retour du réseau.
Traduction terrain : le technicien qui ferme puis rouvre son application sur un chantier sans réseau obtient un écran blanc, avec son travail enfermé dedans.
Cause structurelle : le fichier /web/service-worker.js de la 19.4 est strictement identique à celui de la 19.0. Même taille, diff vide. Aucune évolution du service worker sur quatre releases SaaS.
6. Aucune détection de conflit, et un écrasement silencieux
C'est le point le plus grave, et le plus facile à reproduire. Test à deux utilisateurs sur le même enregistrement :
Il saisit sa valeur et sauvegarde. L'écriture part en file d'attente.
Il saisit une autre valeur sur le même champ et sauvegarde.
La file se rejoue. La saisie du dispatcher disparaît.
Ce qu'on observe à t2 : aucun dialogue de conflit, aucune notification, aucune erreur en file, aucun indicateur dans le systray.
La saisie du dispatcher est détruite sans laisser de trace. web_save exécute un write() nu : pas de contrôle de version, pas de verrou optimiste, pas de comparaison de write_date. Le dernier à synchroniser gagne, y compris quand sa donnée est la plus ancienne.
Corollaire trouvé dans la boucle de synchronisation : une écriture qui échoue est replanifiée avec un marqueur d'erreur, mais la boucle filtre ensuite les entrées portant ce marqueur. Une écriture en erreur n'est donc plus jamais retentée. Elle reste parquée en « Sync issues », à ressaisir à la main.
La synthèse opposable
| Capacité terrain | Odoo 19.4 |
|---|---|
| Éditer un champ sur une fiche déjà ouverte | |
| Supprimer ou archiver hors connexion | |
| Resynchroniser au retour du réseau | |
| Valider une opération métier hors connexion | |
| Prendre une photo | |
| Faire signer le client | |
| Ouvrir une fiche non pré-visitée | |
| Provisionner la tournée du jour | |
| Redémarrer l'application hors connexion | |
| Détecter un conflit d'édition | |
| Rejouer une écriture en erreur | |
| Synchroniser application fermée |
Le volet mobile, souvent confondu avec le sujet
Le responsive fonctionne. En 390 × 844, aucun débordement horizontal, le mode isSmall s'active correctement. Ce n'est pas le problème.
Un client web de 3,58 Mo sur un réseau de chantier, avec 92 % des cibles tactiles trop petites pour un opérateur ganté : ça se paie en minutes perdues à chaque prise de poste.
Et l'IA ?
Le bundle 19.4 contient 83 modules @ai/*. Occurrences du mot offline dans l'ensemble de ces modules : zéro. Occurrences d'IndexedDB : zéro. Les endpoints appelés sont tous serveur, relayés vers un fournisseur externe.
Sans réseau, aucune fonction IA. S'ajoute la question de la souveraineté : photos et transcriptions vocales quittent l'appareil et l'entreprise.
Pourquoi ce n'est pas un bug qui sera corrigé en v20
L'erreur symétrique serait de parier qu'Odoo n'y arrivera jamais. Odoo sait faire de l'offline sérieux, et le Point de Vente le prouve : environ 1 375 lignes de moteur dédié, avec son propre service de données, sa couche IndexedDB et ses modèles relationnels.
Mais ce moteur est entièrement sur mesure pour un seul domaine, construit sur une décennie, et non réutilisable par le client web générique.
Les six points ci-dessus ne sont pas des correctifs de release. Ce sont des problèmes d'architecture distribuée : résolution de conflit, provisionnement de jeux de données, file d'attente de fichiers binaires, rejeu de méthodes métier arbitraires, démarrage sans réseau. Chacun demande un choix produit lourd, sur une surface qui n'est pas le cœur de marché d'Odoo. C'est aussi ce qui sépare une application mobile Odoo sur mesure d'un client web mis en cache.
Odoo comble le cas du bureau avec un réseau instable. Il ne comble pas le cas du terrain sans réseau. Et quand il s'en approchera, ce sera domaine par domaine, comme pour le Point de Vente, pas d'un coup pour tous les workflows.
Un signal va dans ce sens : depuis la 19.2, l'application Field Service est supprimée et fusionnée dans Planning. Les priorités bougent sur la planification, pas sur le terrain déconnecté.
Ce que ça change pour une équipe qui travaille vraiment sans réseau
Chez une PME belge de maintenance industrielle, nous avons remplacé les bons papier par une application terrain conçue hors connexion depuis le départ. Le technicien valide son intervention sans réseau, avec photo et signature, et le bureau ne ressaisit plus rien.
Ce résultat tient à des capacités qu'aucune des six ruptures ci-dessus ne permet : valider une intervention sans réseau, y attacher photo et signature, retrouver son travail après avoir redémarré l'application dans un sous-sol. C'est ce que couvre ASKA Field.
Vérifiez par vous-même, et redatez
Cet audit porte sur saas~19.4+e au 25 juillet 2026. Odoo publie une version SaaS toutes les six semaines environ. Il périme.
La méthode est reproductible en une trentaine de minutes : comparer /web/service-worker.js avec la version précédente, chercher data-available-offline et offline_service dans le bundle web.assets_web.min.js, activer le mode hors connexion puis recharger la page, et tester un conflit d'édition à deux onglets.
Si vous refaites le test sur une version plus récente et que les résultats diffèrent, écrivez-nous. On mettra l'audit à jour et on le dira.
Vos équipes travaillent sans réseau ?
En 30 minutes, nous regardons vos processus de terrain, ce que votre Odoo enregistre aujourd'hui hors connexion et ce qui manque. Vous repartez avec un avis, même sans suite.
Demander un diagnostic de 30 minutesFAQ
Odoo 19.4 fonctionne-t-il hors ligne ?
En partie. Un moteur hors connexion existe depuis la 19.4 et permet d'éditer, supprimer ou archiver un enregistrement déjà ouvert, puis de resynchroniser au retour du réseau. Il ne permet pas de valider une opération métier, d'ajouter une photo ou une signature, d'ouvrir une fiche non visitée, ni de redémarrer l'application sans réseau.
Quelle différence entre le mode hors connexion d'Odoo et une application offline-first ?
Le mode d'Odoo met en cache ce qui a déjà été affiché et rejoue quatre méthodes ORM. Une application offline-first utilise une base locale comme source de vérité, provisionne ses données à l'avance, gère les fichiers binaires et arbitre les conflits d'édition. La première approche couvre un réseau instable, la seconde couvre l'absence de réseau.
Que se passe-t-il si deux personnes modifient la même donnée, l'une hors connexion ?
Sur Odoo 19.4, la dernière synchronisation écrase la précédente sans avertissement, y compris si sa donnée est plus ancienne. Le test est reproductible en deux onglets.
Et Odoo 20, il règle le problème ?
Odoo 20 est sorti après cet audit. Nous avons refait le test des conflits sur Odoo 20.0 le 23 octobre 2026 : le résultat ne change pas, la dernière synchronisation gagne toujours sans alerte. Le détail est dans Odoo 20 hors ligne : quand deux saisies se croisent, laquelle gagne ?.
Les autres points n'ont pas encore été remesurés sur la 20. Ils relèvent de l'architecture distribuée plutôt que du correctif, et le précédent du Point de Vente laisse attendre une résolution domaine par domaine. Si vous utilisez la 20, refaites les quatre tests décrits plus haut : ils prennent une trentaine de minutes.
À lire aussi : Application mobile Odoo : PWA, native ou sur mesure, le guide pour décider.