Documentation fonctionnelle
Guide complet de la plateforme DeepLink — chaque fonctionnalité expliquée en détail, de la création d'un lien à l'analyse des conversions.
Vue d'ensemble de la plateforme
DeepLink est une plateforme open-source d'attribution et de deep linking mobile, alternative à Branch.io, Adjust et AppsFlyer. Elle couvre l'intégralité du cycle de vie d'un utilisateur mobile :
- Acquisition — Créez des liens universels et des bannières intelligentes pour attirer les utilisateurs vers votre app
- Attribution — Identifiez précisément quel canal, campagne ou publicité a généré chaque installation
- Engagement — Suivez les actions in-app (événements) pour mesurer la qualité des utilisateurs acquis
- Monétisation — Calculez la LTV, le ROAS et le payback pour optimiser vos dépenses publicitaires
- Rétention — Analysez les cohortes pour comprendre quand et pourquoi les utilisateurs partent
Toute la plateforme repose sur une chaîne de données : clic → redirection → installation → événements in-app. Le serveur enregistre chaque clic. Le SDK dans l'app remonte les événements. Le dashboard croise les deux pour produire l'attribution, les cohortes, la LTV et le ROAS. Sans événements remontés par le SDK, les pages de suivi (Entonnoir, Attribution, Cohortes, LTV, Parrainages) n'ont rien à afficher.
D'où viennent les données ?
Chaque page du dashboard tire ses données d'une ou plusieurs sources. Comprendre ces sources est essentiel pour savoir pourquoi une page affiche des résultats ou reste vide.
Les 4 sources de données
| Source | Qui l'alimente | Que contient-elle | Pages qui l'utilisent |
|---|---|---|---|
Clics (table clicks) |
Enregistré automatiquement par le serveur à chaque visite sur un lien DeepLink | Horodatage, IP, User-Agent, plateforme, pays, fingerprint, lien source, campagne, source, medium | Vue d'ensemble, Realtime, Liens, Explorateur, Entonnoir, Attribution, Cohortes |
Événements (table events) |
Envoyés par le SDK mobile, le SDK serveur, le Web Tracker, ou l'API directe | Nom (purchase, signup…), propriétés JSON, revenu, devise, fingerprint, user_id |
Événements, Entonnoir, Attribution, Cohortes, LTV & ROAS, Parrainages |
Dépenses pub (table ad_spend) |
Importées manuellement via le dashboard (bouton "+ Ad spend") ou l'API | Date, réseau (Meta, Google…), campagne, montant dépensé, devise | Attribution par canal, LTV/CAC, Payback, ROAS |
Bannières (table banner_events) |
Enregistrées automatiquement par le script banner.js embarqué sur votre site |
Impressions, clics, variante, bannière, groupe A/B | Bannières intelligentes, A/B Tests (type bannière) |
Les événements : le carburant du suivi
Les événements sont la donnée la plus importante de la plateforme après les clics. Sans eux, les pages suivantes restent vides :
- Entonnoir — l'étape "Events" n'a pas de données, le funnel s'arrête à "App Open"
- Attribution — les conversions et le revenu par canal restent à zéro
- Cohortes — la rétention ne peut pas être calculée (pas d'action de retour)
- LTV — la Lifetime Value est nulle sans événements avec
revenue - Parrainages — les claims ne sont pas comptabilisés sans appel explicite à l'API
Au minimum, configurez ces événements dans votre app :
•
signup — inscription d'un nouvel utilisateur•
login — connexion (mesure la rétention)•
purchase — achat, avec revenue en paramètre (alimente la LTV)•
tutorial_complete — fin du tutoriel (mesure l'engagement initial)
Comment envoyer des événements
Il y a 4 façons d'envoyer des événements à DeepLink :
1. Via le SDK mobile (recommandé)
Chaque SDK (iOS, Android, React Native, Flutter, Unity, KMP) expose une méthode trackEvent :
// Événement simple
DeepLink.trackEvent("signup")
// Événement avec propriétés
DeepLink.trackEvent("add_to_cart", properties: [
"product_id": "SKU-789",
"category": "electronics"
])
// Événement avec revenu (alimente la LTV)
DeepLink.trackEvent("purchase", properties: [
"product_id": "SKU-789",
"order_id": "ORD-001"
], revenue: 49.99)
Le SDK rattache automatiquement le fingerprint, le sdk_instance_id et le user_id (si identify() a été appelé). C'est ce qui permet au serveur de relier l'événement au clic d'origine.
2. Via le Web Tracker (dataLayer)
Le Web Tracker est un script JavaScript autonome qui intercepte les événements du dataLayer Google Tag Manager et les transmet à DeepLink. C'est la façon la plus simple de capter les conversions web sans modifier votre code :
<script src="https://votre-serveur/deeplink-tracker.js"
data-tenant="votre-slug"
data-events="purchase,signup,add_to_cart"
async></script>
Comment ça marche :
- Le script est chargé sur votre site web
- Il intercepte
dataLayer.push()(monkey-patch transparent) - Chaque push dont le nom d'événement est dans la liste
data-eventsest capturé - L'événement est envoyé à
POST /api/v1/eventsavec le tenant slug, le nom, les propriétés, et unvisitor_idpersisté en localStorage - Le cookie
dl_vid(posé par le redirect DeepLink) est lu pour l'attribution — ce qui permet de relier un achat web à un clic DeepLink
Vous avez un site e-commerce et une app mobile. Un utilisateur clique sur un lien DeepLink → arrive sur le site web (pas l'app) → achète. Le Web Tracker capte le
purchase du dataLayer et l'attribue au lien DeepLink d'origine grâce au cookie dl_vid.
Attributs du script :
| Attribut | Obligatoire | Description |
|---|---|---|
data-tenant | Oui | Slug du tenant |
data-events | Non | Liste d'événements à capturer (séparés par virgule). Si omis, TOUS les événements dataLayer sont capturés. |
data-server | Non | URL du serveur DeepLink (par défaut : l'origine du script) |
3. Via un tag Google Tag Manager
Le fichier gtm-tag-template.js est un template de tag GTM custom. Il permet de configurer le tracking DeepLink directement dans l'interface GTM, sans code. Les variables GTM (ecommerce, custom dimensions) sont automatiquement mappées vers les propriétés d'événement DeepLink.
4. Via l'API directe (serveur-à-serveur)
Pour les événements côté serveur (webhook Stripe, backend batch), utilisez l'API REST :
POST /api/v1/events
{
"tenant_slug": "votre-slug",
"name": "purchase",
"revenue": 49.99,
"currency": "EUR",
"user_id": "user_123",
"event_id": "evt_abc123", // pour la déduplication
"link_slug": "promo-ete", // pour l'attribution au lien
"properties": { "order_id": "ORD-001" }
}
Endpoint batch pour les files d'attente offline : POST /api/v1/events/batch (max 100 événements par requête).
L'identification : le lien entre clic et événement
Pour que le serveur puisse relier un événement à un clic (et donc attribuer la conversion au bon lien/campagne), il utilise une chaîne d'identité par priorité :
| Identifiant | Comment il arrive | Fiabilité | Impact sur le suivi |
|---|---|---|---|
user_id |
Appelé manuellement via identify("user_123") dans le SDK |
Excellent | Identifie l'utilisateur de façon certaine, même après changement d'IP ou de device. Cohortes et LTV précises. |
sdk_instance_id |
Généré automatiquement par le SDK à la première utilisation | Bon | Unique par appareil. Ne survit pas à une réinstallation. Bon pour les apps sans système de login. |
ip_hash |
Calculé automatiquement par le serveur (SHA-256 de l'IP) | Faible | Partagé entre tous les utilisateurs d'un même réseau WiFi. Peut changer (réseau mobile). Génère des faux positifs dans les cohortes (un utilisateur qui change de réseau apparaît comme un nouvel utilisateur). |
Le dashboard affiche un bandeau d'alerte sur les pages Cohortes et LTV si plus de 20% de vos utilisateurs sont identifiés uniquement par IP. Appelez
identify(userId) dans votre SDK dès que l'utilisateur se connecte pour améliorer la précision.
Concepts clés
Tenant
Un tenant est un espace isolé : ses propres liens, événements, utilisateurs, clés API, configuration. Chaque tenant a un slug unique (ex: demo-10ty40v7) utilisé dans les URL. Un super-admin peut gérer plusieurs tenants depuis le même dashboard.
Lien (Deep Link)
Un lien DeepLink est une URL courte (ex: https://links.example.com/demo/photo-earth) qui redirige intelligemment selon la plateforme :
- iOS avec l'app → Universal Link → l'app s'ouvre directement au bon contenu
- iOS sans l'app → page de redirection → App Store → premier lancement → le SDK appelle
/match→ l'app affiche le bon contenu (deferred deep linking) - Android avec l'app → App Link → l'app s'ouvre
- Android sans l'app → Play Store → install → même flux deferred
- Desktop / Web → fallback vers
web_url
Attribution
L'attribution répond à la question : "quel clic a généré cette conversion ?". DeepLink supporte 5 modèles :
| Modèle | Logique | Usage recommandé |
|---|---|---|
| Last-touch | 100% du crédit au dernier clic | Par défaut. Simple et intuitif. |
| First-touch | 100% au premier point de contact | Mesurer la notoriété et la découverte |
| Linéaire | Crédit réparti également | Vision équilibrée du parcours |
| Time-decay | Plus de crédit aux contacts récents | Campagnes avec cycle de décision long |
| Data-driven | Pondération automatique basée sur les données | Quand vous avez assez de volume |
Paramètres dynamiques & Custom Data
Chaque lien peut porter des données supplémentaires qui sont transmises à l'app via le SDK au moment de la résolution. Il y a deux mécanismes :
Paramètres d'URL dynamiques
Ajoutés à la volée dans l'URL du lien lors du partage :
https://links.example.com/demo/promo-ete?promo_code=SUMMER24&variant=blue
Le serveur capture ces paramètres au moment du clic et les stocke. Le SDK les reçoit lors de la résolution (/resolve ou /match). Utile pour :
- Personnaliser l'expérience d'arrivée dans l'app (afficher le bon produit, appliquer un code promo)
- Tracer la source précise (quel influenceur, quel post social)
- A/B tester des variantes de landing dans l'app
Custom Data (JSON)
Défini lors de la création du lien dans le dashboard (champ custom_data). Ce JSON est transmis tel quel au SDK :
{
"screen": "product_detail",
"product_id": "SKU-789",
"campaign_variant": "hero_image_v2"
}
Page Params dynamiques dans le dashboard
La page Outils → Params dynamiques fournit une analyse des paramètres réellement utilisés :
- Stats : combien de clics portent des params, pourcentage, nombre de clés distinctes
- Top paires clé/valeur : les combinaisons les plus fréquentes et leur volume de clics
- Custom data keys : les clés JSON utilisées dans les custom_data des liens, avec le nombre de liens et de valeurs uniques par clé
Filtrez par lien et par période pour analyser l'usage des params sur une campagne spécifique.
Le Dashboard
Toutes les pages du dashboard
Mapping <div id="page-X"> dans dashboard.html vers la sidebar :
| ID HTML | Sidebar | Rôle |
|---|---|---|
page-overview | Suivi → Overview | KPIs globaux + chart période + top liens |
page-mydash | Suivi → My Dashboard | Layout drag-drop personnalisable user |
page-realtime | Suivi → Realtime | Flux SSE événements temps réel |
page-segments | Suivi → Segments | Définition + analyse cohortes filtrées |
page-explorer | Suivi → Explorer | OLAP table multi-dimensions (pays × OS × source) |
page-cohort | Suivi → Cohortes & rétention | Heatmap rétention + courbes par dimension |
page-funnel | Suivi → Funnels | Analyse tunnel conversion multi-step |
page-ltv | Suivi → LTV | Customer lifetime value par cohorte/canal |
page-cost | Suivi → Coûts & ROI | Coûts ad-platforms × revenus = ROAS |
page-attribution | Suivi → Attribution | Modèles multi-touch (last-click, linear, time-decay) |
page-tester | Outils → Tester | Test live d'un deeplink (preview UA + résolution) |
page-users | Outils → Users | Gestion users tenant + invitations + rôles |
page-workflows | Outils → Workflows | Builder workflows (triggers + actions) |
page-templates | Outils → Templates | CRUD link templates réutilisables |
page-dynparams | Outils → Dynamic params | Gestion query params dynamiques par lien |
page-banners | Outils → Smart Banners | CRUD bannières iOS/Android web→app |
page-ab-tests | Outils → A/B Tests | CRUD A/B + promotion variant gagnant |
page-audit | Outils → Audit log | Journal mutations + filtres + FTS search |
page-settings | Settings (12 onglets) | Cf. section Réglages |
Vue d'ensemble
Page d'accueil après connexion. Source de données : table clicks + events (revenu).
- 4 KPIs : clics (redirections), installations (app opens), taux de conversion, revenu attribué (somme des
revenuedes événements) - Graphique : courbe area SVG du trafic sur la période sélectionnée
- Top destinations : les liens avec le plus de trafic, avec barres de progression
- Par plateforme : répartition iOS / Web / Android en barres horizontales
- Santé technique : uptime API, SDK, webhook DLQ, latence p95
- Alertes récentes : échecs webhook, tests A/B significatifs, nouveaux liens
Realtime
Source : table clicks (dernières 24h) + SSE (Server-Sent Events). Rafraîchi toutes les 5 secondes.
- Visiteurs actifs, événements/minute, clics/minute, pays actifs
- Bar chart des 60 dernières secondes (bars SVG avec opacité proportionnelle)
- Sources live (domaines référents)
- Tableau streaming : chaque nouveau clic apparaît en haut avec une animation fadeIn. Colonnes : type (CLICK/OPEN/INSTALL), ancienneté, slug, device, pays, ID
Explorateur
Requêteur interactif. Source : requêtes SQL générées dynamiquement sur clicks + events.
Sélectionnez des métriques (clics, installations, conversion, revenu) et des dimensions (plateforme, pays, campagne, source), ajoutez des filtres, puis visualisez en graphique ou tableau. Export CSV disponible. Les requêtes peuvent être sauvegardées comme widget sur votre tableau de bord personnalisé.
Mon tableau de bord
Dashboard personnalisable avec widgets glisser-déposer :
- KPI : une métrique avec delta et sparkline
- Graphique : courbe area sur une période
- Liste : top N liens / événements
- Entonnoir : étapes de conversion en barres
Liens
Créer un lien
Depuis la page Contenu → Liens, cliquez Nouveau lien.
| Champ | Description | Impact |
|---|---|---|
slug | Identifiant court dans l'URL. Auto-généré si vide. | Définit l'URL finale du lien |
title / description / image_url | Métadonnées Open Graph | Aperçu dans les partages sociaux (iMessage, WhatsApp, Twitter) |
ios_uri_scheme | URI scheme iOS (ex: myapp://product/123) | Permet d'ouvrir l'app au bon écran |
android_uri_scheme | URI scheme Android | Idem pour Android |
web_url | URL de fallback web/desktop | Où va l'utilisateur s'il n'a pas l'app et n'est pas sur mobile |
campaign / source / medium | Paramètres UTM | Alimentent l'explorateur, l'attribution, les filtres |
tags | Tags libres (séparés par virgule) | Filtrage dans le tableau des liens |
custom_data | JSON libre transmis au SDK | L'app reçoit ces données au moment de la résolution (navigation contextuelle) |
expires_at / max_clicks | Limites de validité | Le lien renvoie une erreur 410 une fois expiré ou cappé |
Tableau des liens
Chaque lien affiche : slug (badge + copie URL), destinations (chips iOS/Android/Web), campagne, statut, clics 7j, CTR, sparkline de tendance. Filtrez par statut, plateforme ou tag. Triez par colonne. Sélection multiple pour les actions en masse (dupliquer, désactiver, supprimer, tagger).
Testeur de lien
Popup accessible depuis le bouton en haut de page. Teste une URL en simulant différents User-Agents. Affiche une trace d'exécution : résolution DNS, TLS, réponse 301, Universal Link match, deferred deep link, fallback store — chaque étape avec un indicateur pass/warn/fail.
QR Codes
Chaque lien dispose d'un QR code généré automatiquement. Accessible depuis l'icône QR dans les actions du tableau.
Modèles
Les modèles (page Outils → Modèles) stockent des presets réutilisables (URI schemes, campaign, custom_data). Appliquez un modèle en un clic lors de la création d'un lien. Affichés en galerie avec preview.
Bannières intelligentes
bar/floating/fullscreen/interstitial, preview live à droite, KPIs impressions/CTR.Principe
Éléments JavaScript embarqués sur votre site web qui incitent les visiteurs mobile à installer votre app. Source de données : impressions et clics enregistrés par le script banner.js.
4 variantes : Bar (bande haut/bas), Interstitial (modal overlay), Fullscreen (plein écran + image), Floating (carte d'angle discrète).
Éditeur
Cliquez sur une bannière pour ouvrir l'éditeur (gauche) avec l'aperçu live (droite, phone mockup). Sections : Général (nom, lien, variante, position), Contenu (texte, bouton, icône), Look & feel (couleurs, rayon, padding), Ciblage (groupe A/B).
Installation
<script src="https://votre-domaine/banner.js"
data-tenant="votre-slug"
async></script>
A/B Tests
Principe
Comparez des variantes de liens ou bannières. L'assignation est persistante (hash SHA-256 déterministe : un même visiteur voit toujours la même variante).
Source de données : clics (test de lien) ou impressions/clics de bannière (test de bannière). Le test compare les taux de conversion entre variantes.
Créer un test
- Type : test de lien ou de bannière
- Métrique : CTR, conversion ou revenu
- Au moins 2 variantes parmi vos liens/bannières existants
- Répartition du trafic (%, somme = 100%)
Résultats
La liste affiche : statut (En cours/Terminé/En pause), uplift (toujours un %, jamais N/A), confiance (barre + % — vert si ≥ 95%), sparkline. Cliquez une ligne pour le détail : tableau par variante, graphique daily, snippet d'intégration.
Significativité : z-test bilatéral, minimum 100 échantillons par variante, uplift > 5%. Niveaux de confiance : 95% et 99%.
Suivi & Analytics
Les pages de cette section n'affichent des données que si des événements sont remontés par le SDK ou le Web Tracker. Si les pages sont vides, vérifiez que votre app appelle bien
trackEvent() et que le tenant_slug est correct. Voir la section Comment envoyer des événements.
Événements
Source : table events. Les schémas sont auto-découverts : dès qu'un nouvel événement arrive avec un nom inconnu, le serveur crée automatiquement le schéma.
La page affiche : catalogue des événements avec nom, nombre de propriétés, volume 7j, sparkline de tendance, statut de validation du schéma (VALID/WARN), date de dernière ingestion.
Déduplication : si un event_id est fourni dans la requête, les doublons sont ignorés (réponse 200 avec deduplicated: true).
Entonnoir de conversion
Source : jointure clicks + events. Le funnel suit le parcours : Redirect → App Open → Deferred → Events.
Chaque étape montre : numéro, nom, drop-off (chip rouge "-X% DROP"), nombre absolu, pourcentage, barre de progression. Deux vues : Barres (design system) et Sankey (diagramme de flux avec drop-off visuel).
Si l'étape "Events" affiche 0, c'est que votre app ne remonte pas d'événements.
Funnel UX — builder drag-drop, saved cards, glossary
Au-delà du funnel par défaut Click → App Open → Events, le Custom builder (FNL-UX livré 2026-05-01) permet de construire des entonnoirs sur mesure.
- Onglet "Custom" dans la page Funnel → + Nouveau funnel.
- Autocomplete events : tape un préfixe → liste des event names réels du tenant (issus de
GET /events/names). Pas de duplication possible. - Drag-drop steps : réordonne par drag natif HTML5. L'ordre détermine le flux de conversion.
- Templates : 4 templates pré-faits (E-commerce, SaaS onboarding, Mobile gaming, Acquisition pub) — clic = remplit le builder en 1 step.
- Save card : nomme et enregistre. Apparaît dans la sidebar "Saved cards".
Saved cards — 5 actions inline
| Action | Effet |
|---|---|
| Open | Affiche le funnel. URL contient ?funnel_id=... partageable. |
| Rename | Modal _promptModal réutilisable (livré FNL-UX). Persistance immédiate. |
| Duplicate | Crée une copie "X (copy)" qu'on peut éditer sans toucher l'original. |
| Share | Copie l'URL deeplink dans le clipboard. |
| Delete | DELETE /api/v1/funnels/:id avec confirm modal. |
Funnel — glossaire des termes
| Terme | Définition |
|---|---|
| Click | Redirect HTTP de l'utilisateur sur le lien (avant install). Source = clicks table. |
| App Open | Déclenchement handleOpenURL() dans l'app native, après ouverture par le SDK. Source = clicks.source = 'resolve'. |
| Window | Délai max pour qu'un step soit attribué au step précédent. Default 30j (paramétrable par funnel). |
| Scope Tenant | Métriques tenant entier (toutes les sources confondues). |
| Scope Lien | Métriques d'un seul lien (drill-down). Sélectionnable via dropdown haut de page. |
| Drop-off | % utilisateurs perdus entre 2 steps. Chip rouge "-X% DROP" si supérieur au seuil de la cellule. |
Default tab et Custom tab partagent le rendu via le helper unifié
_renderFunnelStepsBars (livré FNL-UX). KPIs incluent
conversion globale, taux par step, comparaison previous_period (si
donnée), TTS (Time-To-Step).
Workflows — automatisation par règles
Concept : "Si X arrive → faire Y". Analogie : Zapier ou IFTTT, mais triggéré par les événements DeepLink (clicks, events, deeplinks ouverts).
Anatomie d'un workflow (4 blocs) :
- Trigger : événement qui démarre le workflow (ex.
installreçu,add_to_carttracké). - Condition (optionnelle) : filtre sur les propriétés de l'event (ex.
country == "FR",plan == "premium"). - Action : ce qu'on fait (envoyer une notif push, email, webhook, tag user, etc.).
- Wait (optionnel) : délai entre 2 actions (ex. wait 24h then send email).
5 exemples concrets
- Welcome onboarding :
installreçu → wait 1h → push notif "Bienvenue" → wait 24h → email tutorial. - Cart abandon : event
add_to_cartmais paspurchaseà J+1 → email rappel produit + 10% promo. - Re-engagement : pas de session J-30 → push "On vous a manqué" + lien deferred vers leur dernière page consultée.
- VIP upgrade : ≥3
purchaseevents en 30j → tag user "VIP" + accès feature beta + email gratitude. - Churn warning : retention drop {'>'}40% sur cohort → alerte Slack ops avec liste users à risque.
UI builder : Settings → Workflows → + Nouveau workflow. Voir aussi le playbook 5 templates pour les workflows livrés clé-en-main.
Attribution
Source : clicks + events + optionnellement ad_spend.
Deux vues :
- Attribution par canal — nécessite des dépenses importées. Affiche : canal, dépense, installs, CPA, revenu, ROAS, contribution. Sans dépenses → empty-state avec bouton "Importer".
- Attribution par lien — fonctionne sans dépenses. Sélectionnez un lien + modèle + fenêtre. Affiche : touchpoints (clics/impressions), conversions (click-through/view-through), résultats par modèle (5 modèles).
Cohortes & rétention
Source : clicks (date d'acquisition = date du premier clic par fingerprint) + events (activité de retour). La rétention est calculée comme : "parmi les utilisateurs acquis la semaine S, combien ont produit un événement à D1, D7, D14, D21, D30 ?"
Heatmap : lignes = cohortes (semaines), colonnes = fenêtres de rétention. Cellules colorées par opacité (accent oklch), texte blanc si > 50%. KPIs : D1 moyen, D7 moyen, D30 moyen.
Si la heatmap est vide, c'est que votre app ne remonte pas d'événements réguliers (login, session_start, etc.).
Méthodologie détaillée — comment c'est calculé
Page Suivi → Cohortes & rétention (#page-cohort, dashboard.html:894-940). Deux endpoints serveur :
- Endpoint A (heatmap par jour) —
GET /api/v1/cohort/heatmap?days=30&windows=1,7,30. Renvoie[{ cohort_date, cohort_size, retention: { d1, d7, d30 } }]. La cohorte = users avec ≥ 1 clic ce jour-là (group byDATE(clicks.timestamp)+ identité résolue via cascade). - Endpoint B (rates par dimension) —
GET /api/v1/cohort/rates?dim=source&windows=1,7,30. Renvoie[{ dim_value, total, retention_d1, d7, d30 }]. Permet de comparer les canaux (Facebook 5.6% D7 vs Organic 34.2%).
Identification de l'utilisateur (cascade)
Pour qu'un user d'aujourd'hui soit reconnu comme appartenant à la cohorte d'il y a 7 jours, il faut une identité stable. DeepLink utilise COALESCE(user_id, device_anchor_id, sdk_instance_id, visitor_id, fingerprint, ip_hash) étendue par les identity_aliases nightly (cf. § Architecture / Identity lifecycle).
Limites actuelles & chantier COHORT-PRO
- Windows hardcodées
1/7/30(pas de custom window) - Pas de rétention sur un event spécifique (ex. "% qui ont fait
purchaseà D+7") - Pas de cohorte custom par event (ex. cohorte = "users qui ont fait
signupce jour") - Pas de drill-in (cliquer sur une cellule pour voir les users)
Toutes adressées par chantier COHORT-PRO (statut 🟡 spec ready) — cf. BACKLOG.md.
LTV & ROAS
Source : clicks + events avec revenue + optionnellement ad_spend.
- LTV projetée — toujours visible. Somme des
revenuedes événements par cohorte d'acquisition. Table : date, dimension (campagne/source), utilisateurs, revenu D1/D7/D30/D90, LTV D30. - LTV/CAC, Payback, ROAS — visibles uniquement avec des dépenses pub importées. Calcule : CAC = dépense / installs, payback = jours pour que la LTV dépasse le CAC, ROAS = revenu / dépense.
Si la LTV est à 0, c'est que vos événements n'incluent pas de paramètre revenue. Ajoutez-le dans vos appels trackEvent("purchase", ..., revenue: 29.99).
Parrainages
Source : tables referrals + referral_claims.
Fonctionnement :
- Un admin crée un code de parrainage (ex:
SUMMER24) via le dashboard ou l'API. Le code est associé à unreferrer_idet optionnellement à un type de récompense. - Le code génère une URL courte (
/r/SUMMER24) que le parrain partage. - Quand un filleul clique, s'inscrit et convertit, l'app appelle
POST /api/v1/referrals/claimavec le code et lereferee_id. - Le dashboard affiche les KPIs : codes actifs, parrainages 30j, claims non réglés, taux de conversion. Les claims peuvent être marqués "réglés" par un admin.
SDKs — Intégration dans l'app
SDKs disponibles
| SDK | Langage | Plateforme | Fonctions clés |
|---|---|---|---|
| iOS | Swift | iOS 15+ | Universal Links, deferred, identify, trackEvent, offline queue |
| Android | Kotlin | API 24+ | App Links, deferred, identify, trackEvent, offline queue |
| KMP | Kotlin Multiplatform | iOS + Android | Code partagé iOS/Android |
| React Native | TypeScript | RN 0.73+ | Bridge natif, même API que les SDK natifs |
| Flutter | Dart | Flutter 3.19+ | Plugin avec channels natifs |
| Web JS | JavaScript | Navigateurs | identify, trackEvent, cookie attribution |
| Unity | C# | Unity 2022+ | Deep links, identify, trackEvent, offline queue |
| Node.js | JavaScript | Serveur | trackEvent serveur-à-serveur |
| Python | Python 3.8+ | Serveur | trackEvent serveur-à-serveur |
| Go | Go 1.21+ | Serveur | trackEvent serveur-à-serveur |
Flux d'intégration (4 étapes)
- Initialiser le SDK avec votre
tenant_sluget l'URL du serveur. Le SDK génère unsdk_instance_idet le persiste localement. - Identifier l'utilisateur dès qu'il se connecte :
identify("user_123"). Le SDK attache cet ID à tous les événements et appels ultérieurs. - Gérer les deep links entrants : le SDK intercepte l'URL, appelle
/resolve(Universal Link) ou/match(deferred), et retourne lescustom_datadu lien pour que l'app navigue au bon écran. - Tracker les événements : appelez
trackEvent("purchase", {product: "abc"}, 29.99)à chaque action significative. Le SDK rattache automatiquement le fingerprint et l'identité.
Deferred deep linking — pas à pas
Scénario : l'utilisateur n'a pas l'app installée
1. L'utilisateur clique sur un lien DeepLink
2. Le serveur enregistre le clic avec fingerprint = SHA256(IP + User-Agent)
3. Le serveur redirige vers l'App Store / Play Store
4. L'utilisateur installe l'app et l'ouvre
5. Le SDK appelle POST /api/v1/match avec le fingerprint de l'appareil
6. Le serveur compare avec les clics des dernières 48h (même IP + UA similaire)
7. Match trouvé → le serveur retourne les custom_data du lien
8. L'app navigue vers le bon contenu (ex: page produit spécifique)
Queue offline
Le SDK stocke les événements localement quand il n'y a pas de connexion. Dès que le réseau revient, il les envoie en batch via POST /api/v1/events/batch (max 100 par requête). La déduplication par event_id garantit qu'un événement n'est jamais compté deux fois, même en cas de retry.
Segments d'audience
Les segments (page Outils → Segments) permettent de définir des groupes d'utilisateurs basés sur des critères : pays, plateforme, campagne, source, type de source, période. Ils servent de filtres pour l'explorateur et les rapports. Chaque segment stocke sa définition et peut être prévisualisé avant sauvegarde.
Réglages
/.well-known/apple-app-site-association et /.well-known/assetlinks.json.
Accessibles depuis Admin → Réglages. Navigation dédiée organisée en sections.
Mon compte
Profil (nom, email), changement de mot de passe, 2FA (TOTP). Validation des clics : TTL, seuil de fraude, IPs bloquées.
SSO / SAML
SAML 2.0 pour le SSO d'entreprise (Okta, Azure AD, Google Workspace). Config : Metadata URL + Entity ID. Côté IdP : ACS URL = /api/v1/auth/saml/callback.
Marque
Logo URL + couleur primaire. Utilisés sur la page de redirection, les emails et les bannières. Aperçu live dans les réglages.
Utilisateurs
CRUD complet : créer (mot de passe ou lien d'invitation par email), promouvoir/rétrograder (User/Admin), réinitialiser mot de passe, supprimer.
Clés API
Portées : Full access ou Read-only. La clé n'est affichée qu'une fois à la création. Rotation (nouvelle clé, ancienne invalidée). Révocation définitive.
Webhooks
Multi-endpoint. Chaque endpoint : URL, secret HMAC (X-Deeplink-Signature), API Key (X-Api-Key), filtre d'événements, pause/activation. Pub/Sub en parallèle. Historique des livraisons avec rejeu.
Événements routés : redirect, resolve, deferred, event.*, referral.claim, banner.click, banner.impression, test.ping.
Domaines
CNAME vers le serveur Cloud Run. Vérification DNS intégrée.
Apps mobiles
iOS : Apple Team ID + Bundle ID → génère AASA. Android : Package + SHA-256 → génère assetlinks. Boutons de test intégrés.
Data Warehouse & Export (Sinks)
Les Sinks permettent d'exporter les données vers 6 destinations : BigQuery (streaming), Google Cloud Storage (batch), Amazon S3 (batch), Google Pub/Sub (streaming), email (rapport HTML) et webhook (HTTP).
Modes de déclenchement :
- Manuel (
on_demand) — exécution sur demande via le bouton "Run" ou l'APIPOST /sinks/:slug/run. - Planifié (
cron) — planification cron (min 1h), ex.0 9 * * *pour daily 9h UTC. - Event-driven (
event) — déclenché automatiquement à chaque événement interne (ex.event.created,click.created). Le payload normalisé{event, ts, tenant, props}est envoyé à la destination.
Bouton "Tester la connexion" : dans le formulaire de création ou d'édition d'un Sink, chaque destination dispose d'un bouton pour tester la connexion avant d'enregistrer. Accessible aux admin (anciennement super-admin uniquement).
Note : les destinations BigQuery et Pub/Sub nécessitent le package @google-cloud/bigquery / @google-cloud/pubsub installé côté serveur.
Intégrations
Segment (Write Key), Amplitude (API Key), Mixpanel (Project Token). Les événements sont forwardés en temps réel.
RGPD & conformité
Rétention configurable, purge automatique, demande d'effacement, audit log, IP allowlist, rapports de bugs, logs plateforme.
Flux de redirection complet
L'utilisateur clique sur https://links.example.com/demo/photo-earth?promo=SUMMER
1. Le serveur reçoit GET /demo/photo-earth?promo=SUMMER
2. Il cherche le lien en base (slug=photo-earth, tenant=demo)
3. Il vérifie : actif ? non expiré ? max_clicks non atteint ?
4. Il détecte la plateforme via User-Agent
5. Il enregistre un clic : fingerprint, IP, pays, device, params dynamiques (promo=SUMMER)
6. Il dispatche vers les webhooks (tous les endpoints actifs + Pub/Sub)
7. Il redirige :
iOS avec app → Universal Link → l'app s'ouvre, SDK appelle /resolve
iOS sans app → Page de redirection (logo + couleur marque) → App Store
Android → App Link ou Intent → Play Store si pas installé
Desktop → web_url (https://example.com/product/123)
8. Le SDK dans l'app appelle /resolve (ou /match si deferred)
9. Le serveur retourne : { link_slug, custom_data, params: {promo: "SUMMER"} }
10. L'app navigue au bon écran et applique le code promo
Permission matrix (RBAC)
5 rôles disponibles, attribués au niveau du tenant. Le rôle super-admin est exclusif au tenant main.
| Action | super-admin | admin | editor | viewer | billing |
|---|---|---|---|---|---|
| Lire les liens / analytics | ✅ | ✅ | ✅ | ✅ | — |
| Créer / modifier liens | ✅ | ✅ | ✅ | — | — |
| Supprimer liens | ✅ | ✅ | — | — | — |
| Inviter / supprimer users | ✅ | ✅ | — | — | — |
| Modifier rôles users | ✅ | ✅ | — | — | — |
| API keys (CRUD) | ✅ | ✅ | — | — | — |
| Settings tenant | ✅ | ✅ | — | — | — |
| Webhooks (CRUD) | ✅ | ✅ | ✅ | — | — |
| Workflows (CRUD) | ✅ | ✅ | ✅ | — | — |
| Audit log (lecture) | ✅ (cross-tenant) | ✅ (own tenant) | — | — | — |
| Bug reports | ✅ | ✅ | ✅ | ✅ | — |
| Export (GCS / BigQuery) | ✅ | ✅ | — | — | — |
| Stripe billing portal | ✅ | — | — | — | ✅ |
| Voir factures | ✅ | ✅ | — | — | ✅ |
| Switch tenant (super-admin) | ✅ | — | — | — | — |
| Cloud Logging viewer | ✅ | — | — | — | — |
| Webhook DLQ replay | ✅ | ✅ | ✅ | — | — |
| Run scheduled job manually | ✅ | — | — | — | — |
read:links, write:events, etc.).KPIs & métriques — glossaire
Tous les KPIs affichés dans le dashboard, avec leur source DB et leur formule de calcul.
| KPI | Définition | Source / Formule |
|---|---|---|
| Clicks | Nombre de redirections via un lien | COUNT(*) FROM clicks |
| Unique clicks | Clics uniques par fingerprint | COUNT(DISTINCT fingerprint_hash) |
| App opens | Ouvertures d'app captées par le SDK | COUNT(*) FROM events WHERE event_type='app_open' |
| Installs | Premières app_opens jamais vues pour un device | app_open avec sdk_instance_id jamais vu auparavant |
| Conversion rate | % de clics qui aboutissent à un app_open | app_opens / clicks |
| Match rate (deferred) | % de clicks deferred raccrochés à un install | SUM(matched=true) / SUM(deferred) |
| Revenue | Somme des montants des events avec revenue | SUM(revenue) FROM events |
| ARPU | Average Revenue Per User | revenue / unique_users |
| LTV (D30) | Revenu cumulé par cohorte d'acquisition à J+30 | cf. § Cohortes |
| CAC | Customer Acquisition Cost | ad_spend / installs par campagne |
| ROAS | Return On Ad Spend | revenue / ad_spend |
| Payback period | Jours pour que la LTV dépasse le CAC | première date où cumulative_revenue >= CAC |
| Retention D1/D7/D30 | % de la cohorte revenue à J+N | cf. § Cohortes |
| Funnel conversion | % qui passe d'une étape à la suivante | step_n / step_(n-1) |
| CTR (Smart Banner) | Click-through rate de la bannière | banner_clicks / banner_impressions |
| Time-to-deeplink (TTD) | Délai click → app_open | app_open.timestamp - click.timestamp (ms) |
| Suspicious rate | % de clics flaggés suspicious | SUM(suspicious=true) / COUNT(*) |
| p95 / p99 latency | Latence redirection au percentile 95/99 | histogramme des durées /redirect (Cloud Monitoring) |
Plans & pricing (SaaS managé)
Pricing public — auto-hébergement = open source gratuit (cf. Installation).
Free
€0/mois
- 10 000 clics/mois
- 5 liens actifs
- 1 user
- Sous-domaine
*.deeplink.app - Rétention analytics : 30 jours
- Support communauté
Starter
€49/mois
- 100 000 clics/mois
- Liens illimités
- 3 users
- Custom domain (1)
- Webhooks
- Rétention 90 jours
- Support email (J+2)
Pro
€199/mois
- 1 M clics/mois
- 10 users
- Custom domain (1) + SSL
- Workflows + DLQ
- A/B tests
- Smart Banners
- Export GCS / S3
- Rétention 12 mois
- Support email (J+1) + Slack
Enterprise
Sur devis
- Volume illimité
- Users illimités
- Multi-domaines
- SCIM provisioning
- OIDC SSO
- SAML SSO
- BigQuery export
- Rétention 24+ mois
- SLA 99.9%
- DPA signé + audit RSSI
- Support dédié + onboarding
Glossaire
| Terme | Définition |
|---|---|
| Deep link | URL qui ouvre un contenu spécifique dans une app mobile |
| Deferred deep link | Deep link qui fonctionne même si l'app n'est pas installée — le contexte est récupéré après installation via fingerprint matching |
| Universal Link | Mécanisme iOS (AASA) qui associe un domaine à une app sans redirection navigateur |
| App Link | Équivalent Android des Universal Links (assetlinks.json) |
| Fingerprint | Hash SHA-256 de l'IP + User-Agent, utilisé pour le matching deferred |
| Attribution | Processus qui détermine quel canal/campagne a généré une conversion |
| Cohorte | Groupe d'utilisateurs acquis sur la même période (semaine, mois) |
| LTV | Lifetime Value — revenu total cumulé par utilisateur sur sa durée de vie |
| ROAS | Return On Ad Spend — revenu / dépense publicitaire. Un ROAS de 3× signifie que chaque euro dépensé en pub a généré 3€ de revenu. |
| CPA | Cost Per Acquisition — dépense / nombre d'installations |
| CTR | Click-Through Rate — taux de clic (app_opens / redirects pour les liens, clics / impressions pour les bannières) |
| dataLayer | Objet JavaScript standard de Google Tag Manager. Le Web Tracker DeepLink intercepte ses push pour capturer les conversions web. |
| Custom Data | JSON libre attaché à un lien, transmis au SDK quand l'utilisateur ouvre l'app |
| Params dynamiques | Paramètres d'URL ajoutés au lien au moment du partage (?promo=X), capturés par le serveur et transmis au SDK |
| Webhook | Appel HTTP POST envoyé en temps réel vers une URL externe à chaque événement |
| HMAC | Code d'authentification de message basé sur un hash — vérifie l'intégrité des webhooks |
| Tenant | Espace isolé dans la plateforme (multi-tenant) avec sa propre config, ses clés API et ses données |
| AASA | Apple App Site Association — fichier JSON servi sur /.well-known/ qui permet à iOS d'ouvrir une app directement depuis une URL |
| SKAdNetwork | Framework Apple pour l'attribution post-install avec respect de la vie privée (pas de fingerprint) |
| Incrementality | Mesure de l'effet additionnel d'une campagne (combien de conversions n'auraient pas eu lieu sans la pub) — distingue les conversions causées de celles attribuées par hasard. Mesure rigoureuse via groupes de contrôle (holdout), Bayesian uplift, geo experiments. Cf. analytics destinations (DEF-W4-02 roadmap). |
| MMP | Mobile Measurement Partner — plateforme tierce qui agrège l'attribution mobile cross-réseaux (ex. AppsFlyer, Adjust, Branch). DeepLink se positionne comme alternative MMP open-source/self-hostable, multi-tenant SaaS ou on-prem. |
| IDFA | Identifier for Advertisers — identifiant publicitaire iOS (UUID 36 caractères type 6D92078A-8246-4BA4-AE5B-76104861E7DC). Depuis iOS 14.5 (ATT), nécessite consentement explicite utilisateur. Utilisé par les SDKs ad networks (Meta, Google, TikTok) et Apple Search Ads pour l'attribution post-install. Si non-disponible : fallback fingerprint + SKAdNetwork. |
| GAID | Google Advertising ID (anciennement AAID) — équivalent Android de l'IDFA. Disponible via Google Play Services (com.google.android.gms.ads.identifier.AdvertisingIdClient). Reset possible par l'utilisateur dans les paramètres Android. Depuis Android 13, demande de permission com.google.android.gms.permission.AD_ID. |
| ASA | Apple Search Ads — régie publicitaire d'Apple sur l'App Store. Fournit l'attribution post-install via le SDK iAd / AdServices framework. Tokens ASA capturés côté SDK iOS et envoyés au serveur DeepLink pour résoudre la campagne (cf. ad-networks). |
| Headless | Mode d'utilisation API-only sans dashboard UI. Un client "headless" intègre DeepLink uniquement via l'API REST + SDKs, sans utiliser le dashboard web. Cas d'usage : agences qui white-labellent, intégration backend pure, automation CI/CD. Cf. api-platform. |
| View-through attribution | Attribution donnée à un canal qui a affiché une pub sans clic, suivi d'une conversion plus tard. Window typique : 24h. Génère beaucoup de faux positifs (corrélation ≠ causation) — DeepLink l'attribue avec un poids dégradé via le modèle time_decay (cf. attribution pédagogie). |
| Fingerprint accuracy | Taux de bonnes correspondances click→install via fingerprint IP+UA en l'absence d'IDFA/GAID. Précision typique 60-75% selon le volume + la fenêtre temporelle. Plus la window est courte (≤6h) et le volume faible (≤100 clicks/min/IP), plus la précision augmente. Cf. match.js + STORY-01 fuzzy matching. |
| SAML vs OIDC | Deux protocoles SSO distincts : SAML (Security Assertion Markup Language) — XML-based, ancien, largement utilisé enterprise (Okta, Entra, ADFS) ; OIDC (OpenID Connect) — JSON/JWT-based, moderne, layer au-dessus d'OAuth 2.0 (Google, Auth0, Cognito). DeepLink supporte OIDC nativement (livré). SAML deferred (DEF-W2-09). |