Construire un surveillant de prix et de stock avec MutationObserver
Vous voulez cet article, mais seulement au bon prix — ou vous voulez savoir au moment précis où un produit en rupture revient. Rafraîchir l'onglet toute la journée n'est pas une vie. Cet article construit un surveillant de prix et de stock avec une règle JS JustZix : un MutationObserver surveille l'élément concerné, compare la valeur, et vous alerte quand votre condition est remplie.
Comment fonctionne le surveillant
Le plan a quatre parties, et chacune correspond à une section ci-dessous :
- Choisir un sélecteur stable pour l'élément de prix ou de stock.
- Attacher un
MutationObserverpour réagir aux changements sans interrogation périodique. - Analyser le texte en un nombre ou un booléen comparable.
- Vous notifier — une bannière sur la page ou une notification système — et retenir la dernière valeur.
Tout s'exécute côté client dans l'onglet. Gardez la page produit ouverte (un onglet épinglé est idéal) et la règle fait la surveillance.
Choisir un sélecteur stable
Le surveillant n'est fiable que dans la mesure de son sélecteur. Ouvrez les DevTools, panneau Elements, et trouvez l'élément qui contient le prix. Préférez, dans cet ordre :
- Un point d'ancrage sémantique :
[itemprop="price"],[data-price],[data-testid="product-price"]. Ils changent rarement. - Un ID stable :
#priceblock_ourprice,#product-price. - Une classe significative :
.price-now,.product__price.
Évitez les classes hachées (.css-1a2b3c) et les longues chaînes de descendants — elles cassent au prochain déploiement. Beaucoup de boutiques intègrent aussi des données structurées dans un bloc <script type="application/ld+json"> ; si le DOM visible est en désordre, analyser ce JSON est souvent la voie la plus stable.
Mettre en place le MutationObserver
Un MutationObserver déclenche une fonction de rappel chaque fois que le sous-arbre surveillé change — pas d'interrogation périodique, pas de CPU gaspillé. Surveillez le nœud de prix pour les changements de texte et d'enfants :
const SELECTOR = '[itemprop="price"]'; // votre selecteur stable
const priceEl = document.querySelector(SELECTOR);
if (!priceEl) {
console.warn('[watcher] price element not found - check the selector');
} else {
const observer = new MutationObserver(() => checkPrice(priceEl));
observer.observe(priceEl, {
childList: true,
subtree: true,
characterData: true
});
// Verifie aussi une fois au chargement - le prix peut deja etre une affaire
checkPrice(priceEl);
}
Les boutiques en single-page-app remplacent parfois tout le nœud de prix lors d'une mise à jour. Si votre observateur devient silencieux, observez un conteneur parent stable avec subtree: true et re-interrogez le prix à l'intérieur de la fonction de rappel.
Analyser le prix en un nombre
Le texte de prix est en désordre : symboles monétaires, séparateurs de milliers, virgules décimales. Réduisez-le à un nombre propre avant de comparer :
// Transforme "$1,299.00" ou "1 299,00 zl" en 1299
function parsePrice(text) {
if (!text) return NaN;
// Garde les chiffres, le point et la virgule ; jette le reste
let s = text.replace(/[^0-9.,]/g, '');
// Si la virgule est le separateur decimal, on normalise
if (/,\d{2}$/.test(s)) s = s.replace(/\./g, '').replace(',', '.');
else s = s.replace(/,/g, '');
return parseFloat(s);
}
Comparer à un seuil
Maintenant la logique de décision. Comparez le prix analysé à votre cible et n'alertez que lorsqu'il franchit réellement — et seulement une fois par baisse, pour ne pas être inondé à chaque mutation mineure du DOM :
const TARGET = 999; // alerte quand le prix tombe a/sous ce niveau
const STORAGE_KEY = 'jz-watch-' + location.pathname;
function checkPrice(el) {
const price = parsePrice(el.textContent);
if (Number.isNaN(price)) return;
const last = parseFloat(localStorage.getItem(STORAGE_KEY)) || Infinity;
localStorage.setItem(STORAGE_KEY, String(price));
console.log('[watcher] price now', price, '- last', last);
// Ne se declenche que quand on franchit nouvellement le seuil
if (price <= TARGET && last > TARGET) {
notify('Price drop! Now ' + price + ' (target ' + TARGET + ')');
}
}
Surveiller le retour en stock
Même motif, signal différent. Au lieu d'un nombre, vous surveillez un booléen — le bouton d'achat est-il activé, le libellé « en rupture » a-t-il disparu :
function checkStock() {
const soldOut = document.querySelector('[class*="out-of-stock" i], .sold-out');
const buyBtn = document.querySelector('button[name="add-to-cart"], .add-to-cart');
const inStock = !soldOut && buyBtn && !buyBtn.disabled;
const wasInStock = localStorage.getItem('jz-stock') === 'yes';
localStorage.setItem('jz-stock', inStock ? 'yes' : 'no');
if (inStock && !wasInStock) {
notify('Back in stock! Grab it now.');
}
}
Vous notifier
Une alerte est inutile si vous ne la voyez pas. Utilisez deux canaux : une bannière impossible à manquer sur la page, plus une notification système pour quand l'onglet est en arrière-plan.
function notify(message) {
// 1. Banniere sur la page - toujours visible dans l'onglet
let bar = document.getElementById('jz-watch-bar');
if (!bar) {
bar = document.createElement('div');
bar.id = 'jz-watch-bar';
bar.style.cssText =
'position:fixed;top:0;left:0;right:0;z-index:2147483647;' +
'background:#16a34a;color:#fff;font:600 15px/1.4 sans-serif;' +
'padding:12px 16px;text-align:center;';
document.body.appendChild(bar);
}
bar.textContent = 'JZ watcher: ' + message;
// 2. Notification systeme - fonctionne quand l'onglet est cache
if (Notification.permission === 'granted') {
new Notification('JustZix watcher', { body: message });
} else if (Notification.permission !== 'denied') {
Notification.requestPermission();
}
}
Le z-index de 2147483647 est l'entier 32 bits maximum — il garantit que la bannière se place au-dessus de tout ce que le site affiche. Les notifications système nécessitent une permission, que le navigateur n'accorde qu'à partir d'un geste utilisateur ou d'une origine déjà approuvée, donc la première exécution peut juste la demander ; la bannière vous couvre entre-temps.
Persister la dernière valeur vue
Vous avez vu localStorage utilisé ci-dessus, et il fait un vrai travail. Il survit aux rechargements, donc le surveillant sait si un changement est réellement nouveau. Il dédoublonne aussi les alertes — vous comparez à la valeur stockée et ne notifiez que sur un vrai franchissement. Indexez-le par page (location.pathname) pour que plusieurs surveillants de produits puissent coexister sans s'écraser mutuellement.
Le câbler dans JustZix
- Créez une règle avec le motif d'URL du produit exact, p. ex.
https://shop.example.com/product/12345*. - Collez le script combiné dans l'onglet JS — réglez
SELECTORetTARGETpour ce produit. - Épinglez l'onglet et laissez-le ouvert ; l'observateur réagit chaque fois que la boutique met à jour le DOM.
- Vous voulez une re-vérification périodique même sans changements du DOM ? Ajoutez un
setIntervalqui recharge la page toutes les quelques minutes.
À voir aussi
- Désactiver les dark patterns — retirez la fausse urgence pour voir le vrai prix.
- Simuler les réponses d'API — testez votre surveillant contre un faux flux de prix.
- Cas d'usage de JustZix pour plus d'idées d'automatisation.
Cessez de rafraîchir cet onglet. Installez JustZix, déposez le script de surveillance dans une règle par produit, et laissez le navigateur vous dire au moment précis où le prix est le bon.
Notez cet article
Aucune note — soyez le premier.