umami.track('lecture-terminee', { duree: 42 }) : c’est à peu près tout ce qu’il faut envoyer depuis le navigateur pour qu’une instance Umami auto-hébergée enregistre un événement personnalisé. Le reste du travail se joue côté thème, à décider quand et comment déclencher cet appel sans passer par un plugin d’analytics supplémentaire.
L’instance Umami tournait déjà sur le même serveur que le site, utilisée pour le trafic global. La demande portait sur un indicateur plus fin : savoir si les articles de blog étaient vraiment lus jusqu’au bout, ou seulement survolés. Umami expose une API JavaScript simple pour ce type de mesure, à condition de la piloter soi-même depuis le thème plutôt que d’attendre qu’un plugin le fasse à sa place.
Injecter le script de suivi sans plugin
Le script de suivi Umami s’ajoute via une balise <script> pointant vers l’instance auto-hébergée, avec un attribut data-website-id. Plutôt que de passer par un plugin de gestion de scripts tiers, l’injection se fait directement dans functions.php, accrochée au hook wp_footer :
function wpm_charger_umami() {
if ( is_admin() ) {
return;
}
?>
<script defer src="https://analytics.exemple-interne.fr/script.js"
data-website-id="a1b2c3d4-e5f6-7890-abcd-ef1234567890"></script>
<?php
}
add_action( 'wp_footer', 'wpm_charger_umami' );
Cette approche évite d’ajouter une dépendance supplémentaire pour une seule ligne de script, et garde la main sur les conditions d’affichage : ici, exclue de l’administration via is_admin(), et facilement excluable d’autres gabarits si besoin avec is_page() ou is_singular().
Calculer un temps de lecture qui a du sens

Un simple minuteur démarré à l’ouverture de la page ne dit rien de la lecture réelle : un onglet laissé ouvert en arrière-plan fausserait toutes les statistiques. La mesure retenue combine deux signaux : le temps passé avec l’onglet visible, via l’API document.visibilityState, et un seuil de défilement jusqu’au bas de l’article, repéré via un IntersectionObserver posé sur le dernier paragraphe du gabarit single.php.
const dernierBloc = document.querySelector('.wpm-fin-article');
let debut = Date.now();
let visible = true;
document.addEventListener('visibilitychange', () => {
visible = document.visibilityState === 'visible';
});
const observateur = new IntersectionObserver((entrees) => {
if (entrees[0].isIntersecting && visible) {
const duree = Math.round((Date.now() - debut) / 1000);
umami.track('lecture-terminee', { duree });
observateur.disconnect();
}
});
if (dernierBloc) {
observateur.observe(dernierBloc);
}
Le marqueur .wpm-fin-article est ajouté directement dans le gabarit de l’article, juste après le contenu, via get_template_part. Dès qu’il entre dans la zone visible de l’écran et que l’onglet est actif, l’événement part vers Umami avec la durée réelle passée sur la page.
Lire les résultats sans complexité superflue
Umami affiche les événements personnalisés dans un onglet dédié de son tableau de bord, avec la possibilité de filtrer par propriété — ici, la durée. Sur ce projet, la répartition des durées a permis de repérer deux articles bien plus longs à lire que la moyenne du blog, ce qui a justifié de les découper en plusieurs billets plus courts.
- Aucune table supplémentaire dans la base de données WordPress
- Aucun plugin de mesure de scroll à maintenir
- Un seul point d’entrée à surveiller : la fonction accrochée à
wp_footer
Un événement personnalisé bien pensé vaut mieux qu’un tableau de bord surchargé d’indicateurs qu’on ne consulte jamais.
Pour aller plus loin
Cette mécanique se généralise facilement à d’autres événements : clic sur un lien de téléchargement, ouverture d’un accordéon de FAQ, ou passage d’un formulaire à l’étape suivante. Tant que l’instance Umami reste auto-hébergée et que le volume d’événements reste raisonnable, le thème peut porter lui-même cette instrumentation, sans ajouter de dépendance externe pour quelques lignes de suivi.