Intégrations

Installer le widget changelog

Affichez vos nouveautés dans votre site ou votre application : installation, boutons, API JavaScript et compteur de nouveautés.

Télécharger le Markdown

Mis à jour le

Le widget pealHQ affiche les annonces publiées de votre workspace directement dans votre site ou votre application. Un bouton ouvre le changelog dans une popup centrée ou un panneau latéral, sans quitter la page.

Ce guide peut être partagé avec votre équipe technique ou un agent de développement. Les URLs utilisent un workspace fictif acme : remplacez-les par l’URL générée dans vos réglages. Aucun secret ni clé API n’est nécessaire pour installer le widget sur un portail public.

Préparer le widget

  1. Ouvrez Paramètres → Widget changelog dans l’administration pealHQ.
  2. Choisissez Popup centrée ou Panneau latéral. Le choix est enregistré immédiatement pour le workspace.
  3. Choisissez la couleur de la pastille qui affiche le nombre de nouveautés non vues.
  4. Cliquez sur Tester le widget pour prévisualiser le rendu.
  5. Choisissez Bouton flottant ou Bouton intégré, puis copiez le code proposé.
  6. Installez ce code sur votre site et publiez une annonce dans le changelog pour vérifier le résultat.

Le widget affiche les annonces publiées du workspace, des plus récentes aux plus anciennes, avec leur titre, résumé, contenu et éventuelle image de couverture. Les brouillons sont exclus. Sans annonce publiée, il affiche un message d’attente.

Pour intégrer une vidéo YouTube à une annonce, collez son lien seul sur une ligne, séparé du texte par une ligne vide, ou utilisez le bouton Vidéo YouTube de l’éditeur. La vidéo se lit directement dans le widget, en plein écran si besoin, et s’arrête à sa fermeture. Un lien placé dans une phrase ou avec un libellé reste un simple lien.

Copiez toujours l’URL du script depuis les réglages. Elle peut prendre l’une de ces formes selon votre environnement :

https://acme.pealhq.com/widget/changelog.js
https://preview.example/w/acme/widget/changelog.js

Le choix popup/panneau latéral se fait dans pealHQ, pas dans un attribut du script. Il prend effet lors du prochain chargement du script ; une page déjà ouverte conserve sa configuration. Une mise en cache de 60 secondes peut retarder l’apparition du changement.

Installer un bouton flottant

Collez ce code une seule fois, avant la balise </body> de votre page ou dans le modèle global de votre site :

<script async src="https://acme.pealhq.com/widget/changelog.js"></script>

Le script crée un bouton Nouveautés en bas à droite. Un clic ouvre ou ferme le widget. Le panneau peut aussi être fermé par sa croix ou un clic sur le fond extérieur.

Le script est chargé de manière asynchrone. Sur un portail public, le contenu du changelog est chargé dans une iframe à la première ouverture. Sur un portail privé, un chargement authentifié en arrière-plan initialise aussi le compteur dès le chargement du widget.

Installer un bouton intégré

Placez le bouton à l’endroit souhaité dans votre page, par exemple dans la barre de navigation :

<button type="button" data-peal-changelog-button></button>
<script async data-trigger="false" src="https://acme.pealhq.com/widget/changelog.js"></script>

pealHQ remplit et met en forme ce bouton : icône, libellé Nouveautés et badge de nouveautés non vues. L’attribut data-trigger="false" sur le script supprime le bouton flottant ; il ne désactive pas le widget.

Le contenu et le style du bouton intégré sont remplacés par le widget. Pour conserver votre propre apparence ou votre libellé, utilisez plutôt un bouton personnalisé.

Utiliser votre propre bouton

Ajoutez data-peal-changelog à votre bouton existant :

<button type="button" class="mon-bouton" data-peal-changelog>
    Les dernières améliorations
</button>
<script async data-trigger="false" src="https://acme.pealhq.com/widget/changelog.js"></script>

Ce bouton conserve son contenu et son apparence. Un clic ouvre le widget. Utilisez un vrai bouton avec un libellé accessible ; sur un lien, le widget n’annule pas la navigation par défaut.

Vous pouvez placer plusieurs déclencheurs sur la page avec un seul script. Les boutons ajoutés ultérieurement au DOM sont détectés automatiquement. L’attribut data-peal-unread-count est mis à jour sur les déclencheurs avec le nombre courant de nouveautés non vues ; sur un bouton personnalisé, aucun badge visuel n’est ajouté automatiquement.

Pour afficher un badge dans votre propre bouton, ajoutez un élément data-peal-unread-badge :

<button type="button" class="mon-bouton" data-peal-changelog>
    Nouveautés
    <span class="mon-badge" data-peal-unread-badge aria-hidden="true" style="display:none"></span>
</button>

Le widget y écrit le nombre de nouveautés non vues, l’affiche en inline-flex et le masque à zéro. Il applique aussi la couleur de pastille choisie dans les réglages (fond et texte lisible) et centre le chiffre. La taille, la position, la forme et la hauteur de ligne restent celles de votre CSS ; un line-height: 1 évite qu’il paraisse décalé verticalement.

Piloter le widget en JavaScript

Une fois le script chargé, l’objet window.PealChangelog expose ces méthodes :

MéthodeEffet
open()Ouvre le widget. Sur un portail privé, les annonces sont marquées comme vues après le chargement authentifié réussi.
close()Ferme le widget.
toggle()Alterne entre ouverture et fermeture.
destroy()Retire le widget, le bouton flottant et ses écouteurs ; supprime l’objet global. Les boutons intégrés générés par pealHQ sont vidés.

Exemple à placer dans le gestionnaire de clic d’un bouton de votre application :

function afficherLesNouveautes() {
    if (window.PealChangelog) {
        window.PealChangelog.open();
    }
}

Le script étant asynchrone, l’objet peut ne pas encore exister au premier rendu. Un appel avant son chargement n’est pas mis en attente. Pour ouvrir automatiquement le widget, attendez le chargement du script et la disponibilité du DOM.

Deux événements sont émis sur window lors de l’ouverture et de la fermeture :

function onChangelogOpen() {
    console.log('Le changelog est ouvert');
}

function onChangelogClose() {
    console.log('Le changelog se ferme');
}

window.addEventListener('peal:changelog:open', onChangelogOpen);
window.addEventListener('peal:changelog:close', onChangelogClose);

// Au démontage de votre composant, retirez vos propres écouteurs :
// window.removeEventListener('peal:changelog:open', onChangelogOpen);
// window.removeEventListener('peal:changelog:close', onChangelogClose);

Ces événements ne transportent pas d’identité utilisateur ni de détail d’annonce. L’événement de fermeture est émis au début de l’animation. Les propriétés préfixées par __ servent au fonctionnement interne et ne sont pas des options de configuration.

Intégrer dans React ou une application avec navigation sans rechargement

Chargez le script une fois dans le document HTML ou dans le mécanisme de chargement de scripts de votre framework. Évitez de l’injecter à chaque changement de page.

Pour un bouton React, utilisez un déclencheur personnalisé et laissez pealHQ détecter son apparition :

export function BoutonNouveautes() {
    return (
        <button type="button" data-peal-changelog>
            Nouveautés
        </button>
    );
}

Chargez séparément le script avec data-trigger="false". Ce bouton ne nécessite pas de gestionnaire onClick supplémentaire. Le déclencheur personnalisé évite que pealHQ remplace le contenu d’un élément géré par React.

Une seule instance de widget est disponible par fenêtre. Charger un second script tant que window.PealChangelog existe ne change pas de workspace. Si votre application doit changer de workspace sans recharger la page, appelez destroy(), retirez l’ancienne balise de script, puis chargez celle du nouveau workspace. destroy() ne recharge rien et n’efface pas l’historique des annonces vues. Si vous gérez ce cycle dans un effet React, prévoyez aussi son nettoyage et les chargements asynchrones encore en cours au démontage.

Comprendre le compteur de nouveautés

Le badge des boutons générés par pealHQ indique le nombre d’annonces que ce navigateur n’a pas encore marquées comme vues. Il est masqué à zéro et affiche 99+ au-delà de 99.

  • À la première visite, toutes les annonces publiées récupérées par le widget sont considérées comme non vues. Le compteur fonctionne sur les portails publics et privés.
  • Sur un portail public, l’ouverture marque immédiatement les annonces connues comme vues. Sur un portail privé, elles sont marquées comme vues seulement après le chargement authentifié réussi de la popup. Le chargement du compteur en arrière-plan et un refus d’accès ne les marquent jamais comme vues.
  • L’état est conservé dans le localStorage du site qui intègre le widget, sous la clé peal:changelog:{slug}:seen.
  • Cet état est propre au navigateur et à l’origine du site, et non à un compte pealHQ. Il n’est pas synchronisé entre appareils, sites ou utilisateurs partageant un navigateur.
  • Si le stockage est bloqué, le widget reste utilisable, mais l’état ne persiste pas au rechargement. Effacer les données du site remet aussi le compteur à zéro côté stockage : les annonces réapparaissent alors comme non vues.

Dans l’éditeur d’une annonce, l’option Ouvrir automatiquement cette annonce demande au widget de s’ouvrir au prochain chargement dans chaque navigateur où cette annonce est encore non vue. L’ouverture n’a lieu qu’après publication de l’annonce. Elle fonctionne aussi avec data-trigger="false" et sur un portail privé après la réussite du chargement authentifié en arrière-plan. L’ouverture affiche le changelog complet, puis suit les mêmes règles que toute ouverture pour marquer les annonces comme vues. Plusieurs annonces configurées ainsi ne provoquent qu’une seule ouverture.

Cette option repose sur le même état local que le compteur : elle est ponctuelle par navigateur et par origine, pas par compte. Si plusieurs personnes partagent le même navigateur, la première ouverture vaut pour toutes. Si le stockage est bloqué ou effacé, l’ouverture automatique peut se reproduire lors d’un prochain chargement.

La liste utilisée par le compteur est récupérée au chargement du widget. Pour un portail privé, une iframe invisible passe par la même route authentifiée que la popup, transmet les identifiants publiés au widget, puis est retirée. Aucun identifiant d’annonce privée n’est inclus dans le script public. À chaque ouverture privée, la liste est actualisée après authentification. Il n’y a pas de mise à jour en temps réel : rechargez la page pour actualiser le badge après une nouvelle publication. Fermer puis rouvrir un widget public ne recharge pas son iframe.

Apparence et accès au portail

Le bouton reprend la couleur d’accent du workspace. La couleur de la pastille du compteur se règle séparément dans Paramètres → Widget changelog ; sa couleur de texte s’adapte automatiquement pour rester lisible. Le contenu du widget reprend les couleurs d’accent et de fond lorsque le forfait permet la personnalisation. Le masquage de la mention « Propulsé par pealHQ » dépend également du réglage du workspace et de son forfait. Les liens vers les conditions restent présents.

Le contenu du changelog est isolé dans une iframe : les styles CSS de votre site ne modifient pas son contenu. Pour personnaliser votre déclencheur, utilisez data-peal-changelog. Il n’existe pas d’option de script pour changer le texte du bouton généré, sa position ou sélectionner quelques annonces seulement.

Intégrer un portail privé dans une application authentifiée

Un portail privé reste privé. Le script /widget/changelog.js est accessible sans connexion et ne contient aucune annonce privée ni identifiant d’annonce privée. La page /widget/changelog vérifie l’accès avant de charger les annonces. Sans preuve valide, elle répond HTTP 403 avec un message dans la popup, sans redirection vers une page de connexion.

La session de votre application ne se transmet pas automatiquement à pealHQ. Pour des clients déjà connectés à votre produit, activez le mode SSO dans les paramètres de connexion des clients et utilisez une route de votre backend pour signer leur identité. Ce parcours fonctionne sans seconde connexion et sans cookies tiers : le jeton autorise uniquement la réponse contenant les annonces, sans ouvrir de session pealHQ ni créer de compte.

<button type="button" data-peal-changelog-button></button>
<script async data-trigger="false" data-auth-url="/peal/changelog-widget" src="https://acme.pealhq.com/widget/changelog.js"></script>

data-auth-url désigne une route GET à créer dans votre application, sur le même domaine que la page qui intègre le bouton. Ce n’est pas une route de pealHQ. Adaptez ce chemin à votre backend. Sans data-trigger="false", le même parcours fonctionne avec le bouton flottant.

  1. Au chargement du widget, une iframe invisible appelle cette route pour initialiser le compteur de nouveautés non vues. La popup appelle également cette route à chaque ouverture. Le chargement en arrière-plan ne marque aucune annonce comme vue.
  2. Votre backend vérifie la session et l’autorisation d’accès à cette organisation, puis génère un JWT SSO neuf à partir du compte connecté.
  3. Il répond HTTP 302 vers https://acme.pealhq.com/widget/changelog?token=JWT_ENCODE, avec Cache-Control: no-store et Referrer-Policy: no-referrer. Copiez l’URL du widget affichée dans vos paramètres ; en mode chemin, elle inclut /w/{slug}.
  4. pealHQ valide la signature, l’audience, l’expiration et l’usage unique du jeton, puis charge les annonces dans l’iframe. Le widget récupère leurs identifiants par un échange postMessage vérifiant l’origine pealHQ et la fenêtre émettrice, pour mettre à jour le compteur. Utilisez /widget/changelog, pas /sso/callback, qui ouvre une session pour le portail classique.

Exemple PHP côté serveur, à appeler depuis votre route authentifiée. Les variables PEAL_SSO_AUDIENCE et PEAL_SSO_SECRET viennent des paramètres SSO ; PEAL_WIDGET_URL est l’URL complète de /widget/changelog affichée sur la page d’intégration.

<?php

function pealWidgetUrl(array $authenticatedUser): string
{
    $widgetUrl = getenv('PEAL_WIDGET_URL');
    $audience = getenv('PEAL_SSO_AUDIENCE');
    $secret = getenv('PEAL_SSO_SECRET');
    if (! $widgetUrl || ! $audience || ! $secret || strlen($secret) < 32) {
        throw new RuntimeException('Configuration du widget pealHQ manquante.');
    }

    $encode = static fn (string $value): string =>
        rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
    $now = time();
    $header = $encode(json_encode(['alg' => 'HS256', 'typ' => 'JWT'], JSON_THROW_ON_ERROR));
    $claims = $encode(json_encode([
        'aud' => $audience,
        'sub' => (string) $authenticatedUser['id'],
        'email' => $authenticatedUser['email'],
        'name' => $authenticatedUser['name'],
        'iat' => $now,
        'exp' => $now + 60,
        'jti' => bin2hex(random_bytes(16)),
    ], JSON_THROW_ON_ERROR));
    $signature = $encode(hash_hmac('sha256', "$header.$claims", $secret, true));
    $separator = str_contains($widgetUrl, '?') ? '&' : '?';

    return $widgetUrl.$separator.http_build_query([
        'token' => "$header.$claims.$signature",
    ], '', '&', PHP_QUERY_RFC3986);
}

Dans la route Laravel de votre application, après contrôle de la session et des droits :

return redirect()->away(pealWidgetUrl([
    'id' => $request->user()->id,
    'email' => $request->user()->email,
    'name' => $request->user()->name,
]))->withHeaders([
    'Cache-Control' => 'no-store',
    'Referrer-Policy' => 'no-referrer',
]);

Le secret reste exclusivement sur votre backend. Ne prenez jamais l’identité depuis des paramètres libres du navigateur. Si votre framework met les variables d’environnement en cache, injectez-les via sa configuration. Le guide SSO détaille les champs obligatoires et fournit aussi un exemple Node.js : utilisez le même format JWT, avec l’URL /widget/changelog comme destination.

Le jeton est à usage unique et expire au maximum après 120 secondes ; l’exemple utilise 60 secondes. Générez-le à chaque appel de la route, y compris pour le compteur en arrière-plan, sans mettre en cache la redirection ni placer un jeton fixe dans le snippet. À chaque réouverture, le widget recharge la route de votre backend avec un nouveau jeton. À la fermeture, le contenu privé de l’iframe est retiré. À la déconnexion de votre application, appelez window.PealChangelog?.destroy() pour retirer immédiatement une popup encore ouverte.

Une session pealHQ autorisée reste utilisable sans jeton, notamment pour l’aperçu administrateur. Elle dépend alors des cookies du navigateur : cet aperçu ne remplace pas un test du parcours SSO depuis votre application.

Résoudre un problème d’intégration

SymptômeVérification
Aucun bouton visibleVérifiez le chargement du script dans l’onglet Réseau. Si data-trigger="false" est présent, ajoutez un bouton intégré ou personnalisé.
PealChangelog est absentAttendez la fin du chargement du script. Vérifiez l’URL, les bloqueurs de contenu et la console du navigateur.
Réponse HTML à la place du JavaScript, redirection ou 403Le script doit répondre 200 en JavaScript, même sur un portail privé. Vérifiez l’URL et le déploiement du correctif.
« Connexion nécessaire » dans la popup privéeVérifiez data-auth-url, la session de votre application, le mode SSO et la génération d’un JWT neuf pour la bonne audience. Un jeton expiré, déjà utilisé ou invalide est refusé.
Réponse 404Recopiez l’URL complète depuis les réglages du bon workspace, y compris le préfixe /w/{slug} lorsqu’il existe.
Le bouton fonctionne, mais le panneau est vide ou bloquéVérifiez la requête vers /widget/changelog, les règles d’accès et la politique de sécurité du site intégrateur.
Une annonce manqueVérifiez sa publication et le workspace, puis rechargez la page. Les brouillons ne sont pas affichés.
Le mode ou le badge semble ancienRechargez la page. Sur un portail privé, vérifiez aussi que la route data-auth-url réussit dès le chargement de la page ; le compteur nécessite cet accès authentifié.
Le bouton personnalisé fait aussi naviguer la pageUtilisez <button type="button"> plutôt qu’un lien.
Le widget affiche un autre workspaceGardez une seule instance par fenêtre ; détruisez l’ancienne avant d’en charger une autre.

Si votre site utilise une Content Security Policy (CSP), sa politique doit autoriser le chargement du script depuis l’origine du portail (script-src) et l’iframe depuis cette même origine (frame-src). Pour le parcours privé, frame-src doit aussi autoriser 'self', puisque l’iframe commence par la route de votre application. Le script applique aussi des styles directement aux éléments qu’il crée : une politique interdisant ces styles peut empêcher le rendu. Faites adapter les directives par votre équipe technique à sa politique de sécurité, en vous aidant des erreurs de la console.

Vérifier avant publication

  1. Testez depuis votre site intégrateur, en navigation privée si votre portail est public : l’aperçu dans l’admin peut bénéficier de votre session connectée.
  2. Ouvrez et fermez le widget sur ordinateur et mobile, puis testez le bouton au clavier.
  3. Vérifiez qu’une annonce publiée apparaît et qu’un brouillon reste absent.
  4. Vérifiez que le badge disparaît après ouverture et reste masqué au rechargement dans le même navigateur lorsque le stockage est autorisé.
  5. Publiez une nouvelle annonce et rechargez la page pour vérifier le compteur, y compris sur un portail privé avant toute ouverture de la popup. Vérifiez qu’un accès refusé ne marque pas les annonces comme vues.
  6. Dans une application React, changez de page et vérifiez les nouveaux déclencheurs ainsi que l’absence de bouton flottant en double.
  7. Pour une annonce configurée en ouverture automatique, testez d’abord dans un navigateur qui ne l’a jamais vue, puis rechargez la page et vérifiez que le widget ne s’ouvre pas une seconde fois.

Retrouvez les autres guides dans la documentation et leurs versions partageables dans l’index Markdown.