Passer au contenu principal

Aperçu

Ce tutoriel vous montre comment créer un carrousel d’onboarding multi-étapes en utilisant un seul Message In-App HTML. Contrairement aux carrousels traditionnels qui reposent sur des gestes de balayage, cette approche utilise une navigation par boutons et garde toutes les étapes dans un seul message. Ce que vous allez construire :
  • Un flux d’onboarding en deux étapes avec images, texte et boutons
  • Navigation par boutons (appuyez sur « Suivant » pour avancer, appuyez sur « Commencer » pour fermer)
  • Points indicateurs de progression
  • Transitions en fondu fluides entre les étapes
Carrousel d'onboarding montrant l'écran de bienvenue avec image, texte et bouton Suivant
Utilisez cette approche lorsque vous souhaitez :
  • Guider les utilisateurs à travers un court flux d’onboarding ou d’éducation (2-5 étapes)
  • Exiger que les utilisateurs appuient explicitement sur un bouton pour continuer (pas de gestes de balayage)
  • Garder tout dans un seul Message In-App HTML pour simplifier
  • Fermer automatiquement le message lorsque le flux est terminé
Ce guide utilise un Message In-App HTML pour un contrôle total. Vous pouvez également créer des flux d’onboarding basés sur des cartes avec l’éditeur glisser-déposer—ces cartes sont balayables mais offrent moins de personnalisation.

Prérequis

Avant de commencer, assurez-vous d’avoir :

Comment fonctionne le flux multi-étapes

Avant de plonger dans le code, il est important de comprendre l’approche technique. Cette implémentation utilise un seul Message In-App HTML qui bascule entre les étapes en affichant et masquant le contenu, sans charger plusieurs messages séparés. L’architecture repose sur quatre composants principaux :
1

Conteneurs de carte pour chaque étape

Chaque étape est enveloppée dans un <div> avec la classe card et un ID unique :
<div id="card-0" class="card active">...</div>
<div id="card-1" class="card">...</div>
  • Toutes les cartes existent simultanément dans le DOM
  • Une seule carte est visible à la fois (contrôlée par la classe active)
2

Contrôle de visibilité CSS

Le CSS gère la logique d’affichage/masquage en utilisant l’opacité et les événements de pointeur :
.card {
  opacity: 0;
  pointer-events: none;  /* Empêche l'interaction avec les cartes cachées */
  transition: opacity .25s ease;
}

.card.active {
  opacity: 1;
  pointer-events: auto;  /* Permet l'interaction avec la carte visible */
}
Pourquoi c’est important :
  • opacity: 0 cache la carte visuellement mais la garde dans la mise en page
  • pointer-events: none empêche les clics accidentels sur les cartes cachées
  • transition crée des effets de fondu fluides
3

Gestion d'état JavaScript

La fonction setActive(i) contrôle quelle carte est visible :
function setActive(i) {
  // Mettre à jour la visibilité des cartes
  document.getElementById("card-0").className = i === 0 ? "card active" : "card";
  document.getElementById("card-1").className = i === 1 ? "card active" : "card";

  // Mettre à jour les points de progression
  var dots = document.getElementById("dots").children;
  dots[0].classList.toggle("active", i === 0);
  dots[1].classList.toggle("active", i === 1);
}
Cette fonction :
  • Supprime active de toutes les cartes
  • Ajoute active à la carte cible
  • Met à jour les points indicateurs de progression
4

Écouteurs d'événements des boutons

Les boutons déclenchent la navigation ou la fermeture :
// Avancer à l'étape suivante
document.getElementById("next-0").addEventListener("click", function () {
  setActive(1);
});

// Fermer le Message In-App
document.getElementById("done").addEventListener("click", function (e) {
  if (window.OneSignalIamApi && OneSignalIamApi.close) {
    OneSignalIamApi.close(e);
  }
});
Important : OneSignalIamApi.close(e) est la méthode du SDK OneSignal qui ferme le Message In-App depuis le HTML.
Point clé : C’est un modèle d’application monopage (SPA) au sein d’un Message In-App. Tout le contenu est chargé une fois, et JavaScript gère les changements d’état sans rechargement.

Étape 1 : Créer un nouveau Message In-App HTML

  1. Dans le tableau de bord OneSignal, allez dans Messages → In-App Messages
  2. Cliquez sur New In-App Message
  3. Sélectionnez HTML comme type de message
  4. Choisissez une mise en page Full Screen ou Large (recommandé pour l’onboarding pour maximiser l’impact visuel)
  5. Continuez vers l’éditeur HTML
L’aperçu de l’éditeur HTML peut ne pas refléter entièrement le comportement à l’exécution. Testez toujours sur un appareil réel ou un utilisateur test pour vérifier les animations, le comportement des boutons et l’action de fermeture.

Étape 2 : Ajouter le modèle HTML

Remplacez le contenu de l’éditeur par le modèle ci-dessous. Ce modèle comprend :
  • Code autonome : Tout le HTML, CSS et JavaScript dans un seul fichier
  • Navigation par boutons : Pas de gestes de balayage (plus fiable sur différents appareils)
  • Transitions en fondu : Changements d’opacité fluides entre les étapes
  • Intégration SDK OneSignal : Utilise OneSignalIamApi.close(e) pour fermer le message
  • Optimisé pour mobile : Mise en page responsive avec balise meta viewport
<!doctype html>
<html>
<head>
  <meta charset="UTF-8" />
  <!-- viewport-fit=cover assure la couverture de la zone de sécurité sur les appareils à encoche -->
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
  <style>
    /* Styles de base - reset et police système */
    html, body {
      margin: 0;
      padding: 0;
      background: #ffffff;
      font-family: -apple-system, system-ui;
    }

    /* Conteneur principal avec padding */
    .wrap {
      padding: 28px 22px 24px;
    }

    /* Conteneur de scène - maintient toutes les cartes à la même position */
    .stage {
      position: relative;
      min-height: 74vh;  /* Assure suffisamment d'espace vertical */
    }

    /* Carte - chaque étape du flux d'onboarding */
    .card {
      position: absolute;  /* Toutes les cartes se superposent à la même position */
      inset: 0;            /* Couverture complète de la scène */
      display: flex;
      flex-direction: column;
      align-items: center;
      opacity: 0;               /* Cachée par défaut */
      pointer-events: none;     /* Empêche les clics quand cachée */
      transition: opacity .25s ease;  /* Effet de fondu fluide */
    }

    /* Carte active est visible et interactive */
    .card.active {
      opacity: 1;
      pointer-events: auto;
    }

    /* Typographie */
    h1 {
      margin: 44px 0 12px;
      font-size: 26px;
      text-align: center;
    }

    p {
      margin: 0;
      color: #6b7280;
      text-align: center;
      max-width: 260px;
      line-height: 1.35;
    }

    /* Conteneur d'image - carré avec coins arrondis */
    .image {
      width: 240px;
      height: 240px;
      border-radius: 16px;
      margin: 24px 0 12px;
      background-size: cover;
      background-position: center;
    }

    /* Bouton principal */
    .btn {
      margin-top: auto;  /* Pousse le bouton en bas de la carte */
      width: 100%;
      max-width: 260px;
      height: 52px;
      border: 0;
      border-radius: 12px;
      background: #3b82f6;  /* Bleu - personnalisez selon votre marque */
      color: #fff;
      font-size: 18px;
      font-weight: 600;
    }

    /* Points indicateurs de progression */
    .dots {
      display: flex;
      justify-content: center;
      gap: 8px;
      padding: 12px 0 8px;
    }

    .dot {
      width: 8px;
      height: 8px;
      border-radius: 999px;
      background: #d1d5db;  /* Couleur du point inactif */
    }

    .dot.active {
      background: #6b7280;  /* Couleur du point actif */
      transform: scale(1.15);  /* Légèrement plus grand quand actif */
    }
  </style>
</head>

<body>
  <div class="wrap">
    <div class="stage">

      <!-- ÉTAPE 1 : Carte de bienvenue (commence visible avec la classe "active") -->
      <div id="card-0" class="card active">
        <h1>Bienvenue</h1>
        <div
          class="image"
          style="background-image: url('https://images.pexels.com/photos/6153129/pexels-photo-6153129.jpeg');">
        </div>
        <p>Construisez une habitude quotidienne calme en quelques minutes.</p>
        <button
          id="next-0"
          class="btn"
          data-onesignal-unique-label="onboarding_next_0">
          Suivant
        </button>
      </div>

      <!-- ÉTAPE 2 : Carte de respiration (commence cachée, affichée quand l'utilisateur appuie sur "Suivant") -->
      <div id="card-1" class="card">
        <h1>Respirez</h1>
        <div
          class="image"
          style="background-image: url('https://images.pexels.com/photos/417173/pexels-photo-417173.jpeg');">
        </div>
        <p>Respiration guidée quand vous avez besoin de vous recentrer.</p>
        <button
          id="done"
          class="btn"
          data-onesignal-unique-label="onboarding_done">
          Commencer
        </button>
      </div>

    </div>

    <!-- Indicateur de progression : 2 points, le premier commence actif -->
    <div class="dots" id="dots">
      <div class="dot active"></div>
      <div class="dot"></div>
    </div>
  </div>

  <script>
    (function () {
      /**
       * Basculer entre les cartes en alternant la classe "active"
       * @param {number} i - Index de la carte à afficher (0 ou 1)
       */
      function setActive(i) {
        // Mettre à jour la visibilité des cartes
        document.getElementById("card-0").className = i === 0 ? "card active" : "card";
        document.getElementById("card-1").className = i === 1 ? "card active" : "card";

        // Mettre à jour les points de progression
        var dots = document.getElementById("dots").children;
        dots[0].classList.toggle("active", i === 0);
        dots[1].classList.toggle("active", i === 1);
      }

      // Bouton : Suivant (carte 0 → carte 1)
      document.getElementById("next-0").addEventListener("click", function () {
        setActive(1);
      });

      // Bouton : Commencer (ferme le Message In-App)
      document.getElementById("done").addEventListener("click", function (e) {
        // Vérifier si l'API IAM OneSignal est disponible
        if (window.OneSignalIamApi && OneSignalIamApi.close) {
          OneSignalIamApi.close(e);  // Fermer le message
        }
      });
    })();
  </script>
</body>
</html>

Étape 3 : Personnaliser votre contenu

Sûr à personnaliser

Vous pouvez modifier ces éléments sans casser la fonctionnalité : Contenu :
  • Texte du titre dans les balises <h1>
  • Texte du corps dans les balises <p>
  • Libellés des boutons (Suivant, Commencer)
  • URLs d’images dans les styles background-image: url('...')
Style visuel :
  • Couleurs : Changez l’arrière-plan de .btn, la couleur du texte ou les couleurs des points
  • Espacement : Ajustez le padding et les marges
  • Typographie : Modifiez font-family, font-size, font-weight
  • Rayon de bordure : Mettez à jour les valeurs border-radius pour les boutons et images

Ajouter plus d’étapes

Pour ajouter une troisième étape, suivez ce modèle :
  1. Ajouter la carte HTML :
<div id="card-2" class="card">
  <h1>Votre titre</h1>
  <div class="image" style="background-image: url('votre-url-image');"></div>
  <p>Votre description</p>
  <button id="next-2" class="btn">Suivant</button>
</div>
  1. Ajouter un point de progression :
<div class="dots" id="dots">
  <div class="dot active"></div>
  <div class="dot"></div>
  <div class="dot"></div> <!-- Nouveau point -->
</div>
  1. Mettre à jour la fonction setActive() :
function setActive(i) {
  document.getElementById("card-0").className = i === 0 ? "card active" : "card";
  document.getElementById("card-1").className = i === 1 ? "card active" : "card";
  document.getElementById("card-2").className = i === 2 ? "card active" : "card"; // Nouvelle carte

  var dots = document.getElementById("dots").children;
  dots[0].classList.toggle("active", i === 0);
  dots[1].classList.toggle("active", i === 1);
  dots[2].classList.toggle("active", i === 2); // Nouveau point
}
  1. Mettre à jour l’ID du bouton de l’étape précédente : Changez id="done" en id="next-1" sur le bouton de la carte 1, puis ajoutez un écouteur de clic :
document.getElementById("next-1").addEventListener("click", function () {
  setActive(2);
});
  1. Ajouter le bouton de fermeture à la nouvelle dernière carte (card-2) :
document.getElementById("done").addEventListener("click", function (e) {
  if (window.OneSignalIamApi && OneSignalIamApi.close) {
    OneSignalIamApi.close(e);
  }
});
Gardez les flux d’onboarding courts (maximum 2-4 étapes). Les utilisateurs abandonnent rapidement dans les flux plus longs. Testez les taux de complétion avec le suivi des clics.

Étape 4 : Tester le Message In-App

Liste de vérification des tests

  1. Enregistrez le message dans le tableau de bord OneSignal
  2. Configurez les paramètres de livraison :
    • Définissez les conditions de déclenchement (ex., début de session, vue de page spécifique)
    • Choisissez votre audience cible ou sélectionnez un utilisateur test
  3. Envoyez à un appareil de test :
    • Utilisez les Utilisateurs test pour prévisualiser sans affecter les utilisateurs de production
    • Installez votre application sur un appareil physique (recommandé plutôt que les simulateurs pour un comportement précis)
  4. Vérifiez la fonctionnalité :
    • ✓ La première carte apparaît avec le bon contenu
    • ✓ Le bouton « Suivant » avance à la carte 2
    • ✓ Les points de progression se mettent à jour correctement
    • ✓ Les transitions en fondu sont fluides
    • ✓ Le bouton « Commencer » ferme le message
    • ✓ Le message ne réapparaît pas immédiatement (vérifiez les paramètres de limitation de fréquence)
Les simulateurs/émulateurs peuvent ne pas refléter précisément le comportement de l’appareil réel, en particulier pour les interactions tactiles et les intégrations SDK. Testez toujours sur des appareils physiques avant de lancer en production.

Dépannage des problèmes courants

ProblèmeCause probableSolution
Le message n’apparaît pasConditions de déclenchement non rempliesVérifiez les Déclencheurs de Messages In-App et confirmez que votre utilisateur test remplit les critères
Les boutons ne fonctionnent pasErreurs JavaScript ou IDs non correspondantsVérifiez la console du navigateur pour les erreurs ; vérifiez que les IDs des boutons correspondent aux IDs des écouteurs
Les images ne se chargent pasProblèmes CORS ou URLs invalidesUtilisez des URLs HTTPS ; testez d’abord les URLs d’images dans un navigateur
Le message apparaît mais ne se ferme pasSDK OneSignal non chargéVérifiez que la configuration du Mobile SDK est complète

Prochaines étapes

Suivre l’engagement des utilisateurs :
  • Ajoutez le suivi des clics en utilisant les attributs data-onesignal-unique-label (déjà inclus dans le modèle) pour mesurer l’abandon entre les étapes
  • Consultez les analyses de clics dans Messages → In-App Messages → [Votre message] → Analytics
Personnaliser l’expérience : Personnalisation avancée :
  • Lien profond vers un écran spécifique après la fermeture
  • Utilisez la syntaxe Liquid pour personnaliser les titres avec les noms d’utilisateurs ou attributs
  • Implémentez des tests A/B avec différents flux d’onboarding pour optimiser les taux de complétion