Conception de Tableau de Bord KPI
Patterns complets pour concevoir des tableaux de bord Key Performance Indicator (KPI) efficaces qui orientent les décisions métier.
Quand utiliser cette compétence
- Concevoir des tableaux de bord exécutifs
- Sélectionner des KPI significatifs
- Construire des affichages de monitoring en temps réel
- Créer des vues de métriques spécifiques au département
- Améliorer les mises en page de tableaux de bord existants
- Établir une gouvernance des métriques
Concepts clés
1. Framework KPI
| Niveau | Focus | Fréquence de mise à jour | Audience |
|---|---|---|---|
| Stratégique | Objectifs long terme | Mensuel/Trimestriel | Cadres dirigeants |
| Tactique | Objectifs département | Hebdomadaire/Mensuel | Managers |
| Opérationnel | Quotidien | Temps réel/Quotidien | Équipes |
2. KPI SMART
Spécifique : Définition claire
Mesurable : Quantifiable
Atteignable : Cibles réalistes
Pertinent : Aligné sur les objectifs
Temporellement défini : Période définie
3. Hiérarchie du tableau de bord
├── Résumé exécutif (1 page)
│ ├── 4-6 KPI titres
│ ├── Indicateurs de tendance
│ └── Alertes clés
├── Vues par département
│ ├── Tableau de bord Ventes
│ ├── Tableau de bord Marketing
│ ├── Tableau de bord Opérations
│ └── Tableau de bord Finance
└── Détails approfondis
├── Métriques individuelles
└── Analyse des causes
KPI courants par département
KPI Ventes
Métriques de revenu:
- Monthly Recurring Revenue (MRR)
- Annual Recurring Revenue (ARR)
- Average Revenue Per User (ARPU)
- Taux de croissance du revenu
Métriques de pipeline:
- Valeur du pipeline commercial
- Taux de gain
- Taille moyenne des contrats
- Durée du cycle de vente
Métriques d'activité:
- Appels/E-mails par représentant
- Démos programmées
- Propositions envoyées
- Taux de clôture
KPI Marketing
Acquisition:
- Cost Per Acquisition (CPA)
- Customer Acquisition Cost (CAC)
- Volume de prospects
- Marketing Qualified Leads (MQL)
Engagement:
- Trafic du site web
- Taux de conversion
- Taux d'ouverture/clic d'e-mail
- Engagement social
ROI:
- ROI marketing
- Performance des campagnes
- Attribution par canal
- Période de rentabilisation CAC
KPI Produit
Utilisation:
- Daily/Monthly Active Users (DAU/MAU)
- Durée de session
- Taux d'adoption des fonctionnalités
- Adhérence (DAU/MAU)
Qualité:
- Net Promoter Score (NPS)
- Customer Satisfaction (CSAT)
- Nombre de bugs/problèmes
- Temps de résolution
Croissance:
- Taux de croissance des utilisateurs
- Taux d'activation
- Taux de rétention
- Taux de churn
KPI Finance
Rentabilité:
- Marge brute
- Marge bénéficiaire nette
- EBITDA
- Marge opérationnelle
Liquidité:
- Ratio courant
- Ratio rapide
- Flux de trésorerie
- Fonds de roulement
Efficacité:
- Revenu par employé
- Ratio des dépenses opérationnelles
- Days Sales Outstanding
- Rotation des stocks
Patterns de mise en page du tableau de bord
Pattern 1 : Résumé exécutif
┌─────────────────────────────────────────────────────────────┐
│ TABLEAU DE BORD EXÉCUTIF [Plage ▼] │
├─────────────┬─────────────┬─────────────┬─────────────────┤
│ REVENU │ PROFIT │ CLIENTS │ SCORE NPS │
│ 2,4 M € │ 450 K € │ 12 450 │ 72 │
│ ▲ 12% │ ▲ 8% │ ▲ 15% │ ▲ 5 pts │
├─────────────┴─────────────┴─────────────┴─────────────────┤
│ │
│ Tendance du revenu │ Revenu par produit │
│ ┌───────────────────────┐ │ ┌──────────────────┐ │
│ │ /\ /\ │ │ │ ████████ 45% │ │
│ │ / \ / \ /\ │ │ │ ██████ 32% │ │
│ │ / \/ \ / \ │ │ │ ████ 18% │ │
│ │ / \/ \ │ │ │ ██ 5% │ │
│ └───────────────────────┘ │ └──────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────┤
│ 🔴 Alerte : Taux de churn dépassé le seuil (> 5%) │
│ 🟡 Avertissement : Volume de tickets support 20% au-dessus │
└─────────────────────────────────────────────────────────────┘
Pattern 2 : Tableau de bord métriques SaaS
┌─────────────────────────────────────────────────────────────┐
│ MÉTRIQUES SAAS Jan 2024 [Mensuel ▼] │
├──────────────────────┬──────────────────────────────────────┤
│ ┌────────────────┐ │ CROISSANCE MRR │
│ │ MRR │ │ ┌────────────────────────────────┐ │
│ │ 125 000 € │ │ │ /── │ │
│ │ ▲ 8% │ │ │ /────/ │ │
│ └────────────────┘ │ │ /────/ │ │
│ ┌────────────────┐ │ │ /────/ │ │
│ │ ARR │ │ │ /────/ │ │
│ │ 1 500 000 € │ │ └────────────────────────────────┘ │
│ │ ▲ 15% │ │ J F M A M J J A S O N D │
│ └────────────────┘ │ │
├──────────────────────┼──────────────────────────────────────┤
│ ÉCONOMIE UNITAIRE │ RÉTENTION PAR COHORTE │
│ │ │
│ CAC: 450 € │ Mois 1: ████████████████████ 100% │
│ LTV: 2 700 € │ Mois 3: █████████████████ 85% │
│ LTV/CAC: 6,0x │ Mois 6: ████████████████ 80% │
│ │ Mois 12: ██████████████ 72% │
│ Rentabilisation: │ │
│ 4 mois │ │
├──────────────────────┴──────────────────────────────────────┤
│ ANALYSE DU CHURN │
│ ┌──────────┬──────────┬──────────┬──────────────────────┐ │
│ │ Churn │ Churn │ Churn │ Expansion │ │
│ │ brut │ net │ logo │ │ │
│ │ 4,2% │ 1,8% │ 3,1% │ 2,4% │ │
│ └──────────┴──────────┴──────────┴──────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Pattern 3 : Opérations temps réel
┌─────────────────────────────────────────────────────────────┐
│ CENTRE OPÉRATIONS En direct ● 10:42:15 │
├────────────────────────────┬────────────────────────────────┤
│ SANTÉ SYSTÈME │ STATUT DES SERVICES │
│ ┌──────────────────────┐ │ │
│ │ CPU MEM DISK │ │ ● API Gateway Sain │
│ │ 45% 72% 58% │ │ ● User Service Sain │
│ │ ███ ████ ███ │ │ ● Payment Service Dégradé │
│ │ ███ ████ ███ │ │ ● Database Sain │
│ │ ███ ████ ███ │ │ ● Cache Sain │
│ └──────────────────────┘ │ │
├────────────────────────────┼────────────────────────────────┤
│ DÉBIT DE REQUÊTES │ TAUX D'ERREUR │
│ ┌──────────────────────┐ │ ┌──────────────────────────┐ │
│ │ ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁▂▃▄▅ │ │ │ ▁▁▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁ │ │
│ └──────────────────────┘ │ └──────────────────────────┘ │
│ Actuel : 12 450 req/s │ Actuel : 0,02% │
│ Pic : 18 200 req/s │ Seuil : 1,0% │
├────────────────────────────┴────────────────────────────────┤
│ ALERTES RÉCENTES │
│ 10:40 🟡 Latence élevée sur payment-service (p99 > 500ms) │
│ 10:35 🟢 Résolu : Pool de connexions DB rétabli │
│ 10:22 🔴 Circuit breaker du service de paiement activé │
└─────────────────────────────────────────────────────────────┘
Patterns d'implémentation
SQL pour les calculs KPI
-- Monthly Recurring Revenue (MRR)
WITH mrr_calculation AS (
SELECT
DATE_TRUNC('month', billing_date) AS month,
SUM(
CASE subscription_interval
WHEN 'monthly' THEN amount
WHEN 'yearly' THEN amount / 12
WHEN 'quarterly' THEN amount / 3
END
) AS mrr
FROM subscriptions
WHERE status = 'active'
GROUP BY DATE_TRUNC('month', billing_date)
)
SELECT
month,
mrr,
LAG(mrr) OVER (ORDER BY month) AS prev_mrr,
(mrr - LAG(mrr) OVER (ORDER BY month)) / LAG(mrr) OVER (ORDER BY month) * 100 AS growth_pct
FROM mrr_calculation;
-- Cohort Retention
WITH cohorts AS (
SELECT
user_id,
DATE_TRUNC('month', created_at) AS cohort_month
FROM users
),
activity AS (
SELECT
user_id,
DATE_TRUNC('month', event_date) AS activity_month
FROM user_events
WHERE event_type = 'active_session'
)
SELECT
c.cohort_month,
EXTRACT(MONTH FROM age(a.activity_month, c.cohort_month)) AS months_since_signup,
COUNT(DISTINCT a.user_id) AS active_users,
COUNT(DISTINCT a.user_id)::FLOAT / COUNT(DISTINCT c.user_id) * 100 AS retention_rate
FROM cohorts c
LEFT JOIN activity a ON c.user_id = a.user_id
AND a.activity_month >= c.cohort_month
GROUP BY c.cohort_month, EXTRACT(MONTH FROM age(a.activity_month, c.cohort_month))
ORDER BY c.cohort_month, months_since_signup;
-- Customer Acquisition Cost (CAC)
SELECT
DATE_TRUNC('month', acquired_date) AS month,
SUM(marketing_spend) / NULLIF(COUNT(new_customers), 0) AS cac,
SUM(marketing_spend) AS total_spend,
COUNT(new_customers) AS customers_acquired
FROM (
SELECT
DATE_TRUNC('month', u.created_at) AS acquired_date,
u.id AS new_customers,
m.spend AS marketing_spend
FROM users u
JOIN marketing_spend m ON DATE_TRUNC('month', u.created_at) = m.month
WHERE u.source = 'marketing'
) acquisition
GROUP BY DATE_TRUNC('month', acquired_date);
Code Python Dashboard (Streamlit)
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
st.set_page_config(page_title="KPI Dashboard", layout="wide")
# Header with date filter
col1, col2 = st.columns([3, 1])
with col1:
st.title("Executive Dashboard")
with col2:
date_range = st.selectbox(
"Period",
["Last 7 Days", "Last 30 Days", "Last Quarter", "YTD"]
)
# KPI Cards
def metric_card(label, value, delta, prefix="", suffix=""):
delta_color = "green" if delta >= 0 else "red"
delta_arrow = "▲" if delta >= 0 else "▼"
st.metric(
label=label,
value=f"{prefix}{value:,.0f}{suffix}",
delta=f"{delta_arrow} {abs(delta):.1f}%"
)
col1, col2, col3, col4 = st.columns(4)
with col1:
metric_card("Revenue", 2400000, 12.5, prefix="$")
with col2:
metric_card("Customers", 12450, 15.2)
with col3:
metric_card("NPS Score", 72, 5.0)
with col4:
metric_card("Churn Rate", 4.2, -0.8, suffix="%")
# Charts
col1, col2 = st.columns(2)
with col1:
st.subheader("Revenue Trend")
revenue_data = pd.DataFrame({
'Month': pd.date_range('2024-01-01', periods=12, freq='M'),
'Revenue': [180000, 195000, 210000, 225000, 240000, 255000,
270000, 285000, 300000, 315000, 330000, 345000]
})
fig = px.line(revenue_data, x='Month', y='Revenue',
line_shape='spline', markers=True)
fig.update_layout(height=300)
st.plotly_chart(fig, use_container_width=True)
with col2:
st.subheader("Revenue by Product")
product_data = pd.DataFrame({
'Product': ['Enterprise', 'Professional', 'Starter', 'Other'],
'Revenue': [45, 32, 18, 5]
})
fig = px.pie(product_data, values='Revenue', names='Product',
hole=0.4)
fig.update_layout(height=300)
st.plotly_chart(fig, use_container_width=True)
# Cohort Heatmap
st.subheader("Cohort Retention")
cohort_data = pd.DataFrame({
'Cohort': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
'M0': [100, 100, 100, 100, 100],
'M1': [85, 87, 84, 86, 88],
'M2': [78, 80, 76, 79, None],
'M3': [72, 74, 70, None, None],
'M4': [68, 70, None, None, None],
})
fig = go.Figure(data=go.Heatmap(
z=cohort_data.iloc[:, 1:].values,
x=['M0', 'M1', 'M2', 'M3', 'M4'],
y=cohort_data['Cohort'],
colorscale='Blues',
text=cohort_data.iloc[:, 1:].values,
texttemplate='%{text}%',
textfont={"size": 12},
))
fig.update_layout(height=250)
st.plotly_chart(fig, use_container_width=True)
# Alerts Section
st.subheader("Alerts")
alerts = [
{"level": "error", "message": "Churn rate exceeded threshold (>5%)"},
{"level": "warning", "message": "Support ticket volume 20% above average"},
]
for alert in alerts:
if alert["level"] == "error":
st.error(f"🔴 {alert['message']}")
elif alert["level"] == "warning":
st.warning(f"🟡 {alert['message']}")
Bonnes pratiques
À faire
- Limiter à 5-7 KPI - Se concentrer sur ce qui compte
- Afficher le contexte - Comparaisons, tendances, cibles
- Utiliser des couleurs cohérentes - Rouge=mauvais, vert=bon
- Activer le zoom - Du résumé au détail
- Mettre à jour correctement - Correspondre à la fréquence des métriques
À ne pas faire
- Ne pas afficher de métriques de vanité - Se concentrer sur les données exploitables
- Ne pas surcharger - L'espace blanc aide la compréhension
- Ne pas utiliser de graphiques 3D - Ils déforment la perception
- Ne pas cacher la méthodologie - Documenter les calculs
- Ne pas ignorer le mobile - Assurer un design réactif
Dépannage
MRR affiché sur le tableau de bord contredit le chiffre de la finance
La cause la plus courante est le traitement incohérent des plans annuels. La finance peut faire une prorata sur un taux quotidien tandis que le tableau de bord normalise au mois. Aligner sur une formule unique et la documenter directement sur la carte KPI :
-- Formule explicite affichée dans l'infobulle / dictionnaire des données
-- Plans annuels : diviser la valeur totale du contrat par 12
-- Plans trimestriels : diviser par 3
-- Plans mensuels : utiliser tel quel
CASE subscription_interval
WHEN 'monthly' THEN amount
WHEN 'quarterly' THEN amount / 3.0
WHEN 'yearly' THEN amount / 12.0
END AS normalized_mrr
Le tableau de bord affiche du vert mais l'équipe produit signale des plaintes d'utilisateurs
Le tableau de bord suit probablement la disponibilité du système (indicateur retardé) mais pas les métriques de qualité perçues par l'utilisateur. Ajouter des métriques de qualité perçue par le client aux côté des métriques d'infrastructure :
| Infrastructure (vert) | Perçues par l'utilisateur (ajouter) |
|---|---|
| Uptime API 99,9% | Temps de chargement page P95 |
| Taux d'erreur 0,1% | Taux de complétude des tâches |
| Profondeur de queue normale | Volume de tickets de support |
La cohorte de rétention semble plate — pas de variation entre cohorts
Vérifier que la requête de cohorte partitionne correctement par mois de création. Un bug courant est utiliser created_at::date au lieu de DATE_TRUNC('month', created_at), ce qui groupe par jour et crée des cohorts trop petites pour montrer les tendances :
-- Mauvais : trop granulaire, cohorts trop petites
DATE_TRUNC('day', created_at) AS cohort_date
-- Correct : cohorts mensuelles
DATE_TRUNC('month', created_at) AS cohort_month
Le tableau de bord temps réel surcharge la base de données
Un tableau de bord en direct s'actualisant toutes les 10 secondes avec du SQL de cohorte complexe dégraderas la performance des requêtes de production. Séparer les charges de travail OLAP d'OLTP en écrivant des métriques préagrégées dans une table de résumé via un travail programmé, et avoir le tableau de bord lire à partir de celle-ci :
# Programmé toutes les 5 minutes via cron/Celery
def refresh_mrr_summary():
conn.execute("""
INSERT INTO kpi_snapshot (metric, value, snapshot_at)
SELECT 'mrr', SUM(...), NOW()
FROM subscriptions WHERE status = 'active'
ON CONFLICT (metric) DO UPDATE SET value = EXCLUDED.value
""")
Les seuils d'alerte se déclenchent constamment, l'équipe les ignore
Les seuils statiques définis une fois et jamais révisés causent une fatigue aux alertes. Utiliser des seuils dynamiques basés sur des moyennes mobiles pour que les alertes se déclenchent uniquement quand la métrique s'écarte significativement de sa propre base :
# Alerte si la valeur actuelle est > 2 écarts-types de la moyenne mobile 30 jours
def is_anomalous(current: float, history: list[float]) -> bool:
mean = statistics.mean(history)
stdev = statistics.stdev(history)
return abs(current - mean) > 2 * stdev
Compétences connexes
data-storytelling- Transformer les découvertes du tableau de bord en narratifs qui orientent les décisions exécutives