Le reporting mensuel est un cas d'école de la tâche qui devrait être automatisée depuis longtemps. Pourtant, dans 90% des PME et startups que je rencontre, c'est encore fait à la main. Excel ouvert, onglets copiés-collés, email rédigé, PDF exporté. Chaque mois. 3 à 5 heures perdues.
Ce post décrit le pipeline exact que j'ai construit pour un client SaaS B2B — passé de 4h de reporting manuel à 10 minutes de vérification humaine.
Anatomie du problème
Avant l'automatisation, voici ce que l'équipe faisait chaque fin de mois :
- Export manuel depuis Stripe (MRR, churn, nouveaux clients)
- Export depuis HubSpot (pipeline, deals closés, activité commerciale)
- Export depuis Google Analytics (trafic, conversions, sources)
- Consolidation dans un Google Sheet
- Rédaction du rapport narratif par le CEO (~1h)
- Envoi par email aux investisseurs + partage Notion
Chaque étape manuelle = risque d'erreur, oubli de donnée, délai.
Architecture du pipeline
[Cron : 1er du mois, 8h00]
↓
[n8n : Pull Stripe API] [n8n : Pull HubSpot API] [n8n : Pull GA4 API]
↓ ↓ ↓
[Normalisation + agrégation des métriques clés]
↓
[GPT-4o : Analyse narrative + détection d'anomalies]
↓
├→ [Notion : Mise à jour de la page rapport]
├→ [Slack : Résumé #reporting avec thread détaillé]
└→ [Email : PDF rapport aux investisseurs via Resend]
Temps d'exécution total : 3 à 7 minutes selon la volumétrie des APIs.
Le nœud GPT-4o — le vrai différenciateur
Le pull de données, n'importe quel outil peut le faire. Ce qui change tout, c'est la couche d'analyse.
Voici le prompt que j'utilise (simplifié) :
Tu es analyste financier senior. Voici les métriques de [Entreprise] pour [Mois] :
MRR : {{mrr}} (vs {{mrr_prev}} le mois précédent)
Churn : {{churn_rate}}%
Nouveaux clients : {{new_customers}}
Pipeline commercial : {{pipeline_value}}€
Trafic web : {{sessions}} sessions ({{conversion_rate}}% conversion)
Génère :
1. Un résumé exécutif de 3 phrases (ton factuel, chiffres précis)
2. Les 2-3 signaux positifs à souligner
3. Les 1-2 points d'attention à surveiller
4. Une recommandation actionnelle pour le mois suivant
Format JSON strict avec les clés : summary, positives, warnings, recommendation
GPT-4o retourne du JSON structuré, que n8n utilise ensuite pour formater les différents canaux (Slack avec emojis, Notion en markdown, email en HTML propre).
Le détail qui change tout : la détection d'anomalies
En plus du résumé, j'ajoute une étape de détection automatique :
// Nœud n8n "Function" — avant GPT-4o
const prev = $input.item.json.prev_month
const curr = $input.item.json.current_month
const anomalies = []
if (curr.churn_rate > prev.churn_rate * 1.5) {
anomalies.push(
`⚠️ Churn en hausse de ${Math.round((curr.churn_rate / prev.churn_rate - 1) * 100)}%`
)
}
if (curr.mrr < prev.mrr * 0.95) {
anomalies.push(`📉 MRR en baisse de ${Math.round((1 - curr.mrr / prev.mrr) * 100)}%`)
}
if (curr.conversion_rate < 0.8) {
anomalies.push(`🔴 Taux de conversion critique : ${curr.conversion_rate}%`)
}
return [{ json: { ...curr, anomalies } }]
Si des anomalies sont détectées, une alerte séparée est envoyée immédiatement sur le canal Slack #alertes, sans attendre la fin du pipeline complet.
Résultat réel — 3 mois après déploiement
- Temps libéré : 4h → 10 min de vérification humaine par mois
- Qualité : 0 donnée manquante depuis le déploiement (vs 2-3 erreurs/mois avant)
- Rapidité : rapport disponible à 8h01 le 1er du mois, sans que personne n'ait allumé son ordinateur
- ROI : le coût du pipeline est amorti en 2 mois si on valorise le temps à 100€/h
Que se passe-t-il si une source de données tombe ?
C'est la question qu'on me pose systématiquement après la démo, et c'est la bonne question. Un pipeline qui pull 3 APIs externes à 8h00 pile va, un jour ou l'autre, tomber sur une API en maintenance ou une erreur 500 passagère.
La règle que j'applique : un rapport partiel avec une alerte claire vaut mieux qu'un rapport qui plante silencieusement.
// Nœud n8n "Function" — wrapper autour de chaque pull d'API
try {
const data = await pullStripeData()
return [{ json: { source: 'stripe', status: 'ok', data } }]
} catch (err) {
return [{ json: { source: 'stripe', status: 'failed', error: err.message } }]
}
Chaque branche du pipeline (Stripe, HubSpot, GA4) est enveloppée de la même façon. En sortie, le nœud d'agrégation vérifie le statut de chaque source :
- Si toutes les sources répondent : rapport complet, comme d'habitude.
- Si une source échoue : le rapport part quand même, avec une mention explicite ("Données HubSpot indisponibles — pipeline commercial non inclus ce mois-ci") plutôt qu'un chiffre à zéro qui pourrait être interprété comme une vraie chute d'activité.
- Une alerte technique séparée part sur un canal Slack
#ops(pas celui des investisseurs) pour que quelqu'un aille vérifier manuellement avant le mois suivant.
Ce garde-fou a servi une fois en production : l'API HubSpot a eu une interruption de 40 minutes le matin du 1er. Le rapport est parti à l'heure, avec la mention adaptée, et personne côté investisseurs ne s'en est même rendu compte.
Ce que ce pipeline ne fait pas (encore)
- Générer des graphiques automatiquement (possible avec Chart.js + screenshot via Playwright, mais ça complexifie)
- Envoyer à des audiences segmentées avec des niveaux de détail différents (possible avec des branches n8n)
- S'adapter aux changements de structure d'API (nécessite une maintenance si Stripe ou HubSpot modifie ses endpoints)
Votre reporting prend encore plusieurs heures chaque mois ?
Ce type de pipeline prend 2 à 3 semaines à construire proprement, tests inclus. Décrivez vos sources de données et votre processus actuel — je reviens avec une architecture adaptée à votre cas sous 24h.