← Tous les articles

API et helpers

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 :

  1. Choisir un sélecteur stable pour l'élément de prix ou de stock.
  2. Attacher un MutationObserver pour réagir aux changements sans interrogation périodique.
  3. Analyser le texte en un nombre ou un booléen comparable.
  4. 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 :

É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

  1. Créez une règle avec le motif d'URL du produit exact, p. ex. https://shop.example.com/product/12345*.
  2. Collez le script combiné dans l'onglet JS — réglez SELECTOR et TARGET pour ce produit.
  3. Épinglez l'onglet et laissez-le ouvert ; l'observateur réagit chaque fois que la boutique met à jour le DOM.
  4. Vous voulez une re-vérification périodique même sans changements du DOM ? Ajoutez un setInterval qui recharge la page toutes les quelques minutes.

À voir aussi

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.

Essayez vous-même

Installez JustZix et collez n'importe quel snippet de cet article. Deux minutes de zéro à une règle fonctionnelle sur tous vos appareils.

Obtenir JustZix

Fonctionnalités · Comment ça marche · Exemples · Cas d'usage