- Bastien Vélitchkine
- Posts
- House of Data - Épisode 1 : Théorie
House of Data - Épisode 1 : Théorie
Mon blueprint pour construire un système complet de détection, activation et analyse des signaux d'intent.
Détecter un signal d’intent par-ci par-là, envoyer des notifications dans Slack et laisser les sales s’en dépatouiller, c’est pas mal — c’est même indispensable au début.
Mais ensuite, que se passe-t-il lorsqu’on veut :
construire un scoring basé sur les signaux qu’on détecte ?
distribuer les signaux dans le CRM en plus de Slack ?
accéder à l’historique des signaux détectés ?
Ce que je m’apprête à partager avec vous est rare et mal documenté.
On passe à l’échelle.
On arrête le bricolage.
Changement de paradigme.
Le but → construire un système avec lequel il est simple :
d’exploiter les signaux (les distribuer dans le CRM, construire un scoring, …)
d’itérer (ajouter de nouveaux signaux, changer de méthode de scoring, …)
d’analyser les signaux détectés (combien, à quelles dates, de quels types, …)

c’est ce que j’avais initialement écrit ici, dans l’introduction…
…pis, quelques semaines plus tard, on m’a arraché le clavier des mains pour me forcer à contempler le pavé de 6km de long que je venais encore de vous pondre.
J’ai vu deux options :
continuer de mentir
ou faire des mèmes et diviser la newsletter en deux parties.
On est déjà à 2 mèmes rien que dans l’intro, vous comprendrez que j’ai choisi la deuxième option 🌝
J’ai donc divisé la newsletter en deux parties :
la première, théorique, où :
je parle des deux briques essentielles à la construction du fameux système de signaux d’intent, et pourquoi c’est pas juste une histoire d’automatisation
j’expose mon blueprint pour construire un tel système (à la fois pour en poser les fondations, mais aussi pour itérer dessus)
la deuxième, pratique, où on traitera 3+ signaux d’intents en s’appuyant sur mon travail lors d’une mission avec Bulldozer (vous la recevrez la semaine prochaine).
Donc, sans plus attendre, voici le premier épisode de la série :

Deux briques
Automatisation et…
Instinctivement, lorsqu’on entend “signaux d’intent”, on pense “automatisation”, “Zapier” et “n8n”. On pense à la manière dont les données cheminent de leur source à leur destination — de Welcome to the Jungle à Slack par exemple.
La brique automatisation est essentielle, même pour construire le genre de système dont il est question ici — je ne dirai pas le contraire.
Mais il y a une autre brique, toute aussi importante, dont il faut se préoccuper en amont de l’automatisation.

la brique stockage
Pourquoi des notifications ne suffisent pas
Admettons que vous souhaitiez scorer les entreprises selon plusieurs critères :
statiques → le secteur de l’entreprise, sa localisation, etc.
dynamiques → 🙂 signaux d’intent — typiquement, le signal “entreprise recrute un head of sales”, si vous êtes éditeur CRM.
Bon, maintenant, imaginez que cette entreprise n’ait pas émis un unique signal, mais PLEIN de signaux différents et que le seul endroit où vous en ayez gardé la trace soit dans Slack, sous forme de messages.

typiquement dans un canal comme celui-ci
Bonne chance pour récupérer le détail des signaux puis les intégrer à votre score.
Bonne chance pour construire des dashboards incluant les signaux détectés.
Bonne chance pour ne pas créez de signaux en double dans le canal Slack.
Où stocker les signaux alors ?
Je vous ai convaincus que tout envoyer dans Slack n’était pas soutenable. Il me reste à vous convaincre que le bon endroit où stocker les signaux est une base de données.
Reprenons l’exemple du scoring.
Imaginez qu’en une ligne de code, vous puissiez récupérer la liste de tous les signaux émis par une entreprise donnée (id=123456789
) entre le 14/02/2025 et aujourd’hui.
SELECT
signal_id,
company_id,
detection_date,
"website visit" as signal_type -- on récupère les colonnes qui nous intéressent
FROM website_visit_intent_signals -- dans la table des signaux website visits
WHERE (
detection_date >= "2025-02-14" -- après le 14 février
AND company_id=123456789 -- et émis par l'entreprise 123456789
)
UNION -- à tous les résultats du dessus, on ajoute :
SELECT
signal_id,
company_id,
detection_date,
"job offer" as signal_type -- les mêmes colonnes
FROM job_offer_intent_signals -- mais de la table des signaux job offers
WHERE (
detection_date >= "2025-02-14" -- après la saint valentin, à nouveau
AND company_id=123456789 -- émis par la même entreprise
);
Imaginez que grâce à cette simple commande, vous obteniez ce genre de tableaux :
signal_id | company_id | detection_date | signal_type |
---|---|---|---|
web-vis-245 | 123456789 | 2025-02-14 | website visit |
web-vis-311 | 123456789 | 2025-02-16 | website visit |
job-off-44 | 123456789 | 2025-02-16 | job offer |
web-vis-980 | 123456789 | 2025-02-21 | website visit |
… | … | … | … |
Je pense que vous sentez à quel point construire le score de l’entreprise 123456789
sera simple; à quel point construire le dashboard du nombre de signaux détectés par mois sera simple; à quel point vérifier que la “website visit” du 16/02/2025 n’est pas un doublon sera simple.
Or, pour que tout ceci soit aussi simple, il faut stocker les signaux dans une base de données.
Je sais que le mot fait peur.
Je sais à quel point on aime les Google Sheets.
Mais c’est pas tenable (déjà parce qu’une GSheet ne vous empêche pas de créer des doublons, contrairement à une bdd bien configurée).
Bref, voici venu le moment de prouver qu’on mérite le “engineer” dans “growth engineer”.
En passant, si le sujet du scoring vous intéresse, voici comment :
Quelle base de données ?
Il faut stocker les signaux en base de données. Ok, soit.
Mais quelle type de base de données ?
Évidemment, plusieurs solutions sont possibles, mais il faut garder deux choses en tête :
que les signaux sont liés à des entreprises ou contacts émetteurs
qu’on veut tantôt stocker des nombres entiers, tantôt des dates, tantôt des strings, …
Donc, naturellement on privilégiera une base de données :
relationnelle (une base de données dans laquelle on peut indiquer que tel signal de telle table est lié à tel contact de telle autre table, lui-même lié à telle entreprise de telle autre)
typée (dans laquelle on peut stocker des strings, des booléens, des dates, des objets, …).
Je recommande fortement PostgreSQL, mais on verra une autre option dans la partie 2.
Blueprint
Je viens de vous montrer pourquoi le système qu’on s’apprête à construire a besoin d’une brique stockage en plus de sa brique d’automatisation habituelle.
Mon blueprint se divise en quatre étapes :
architecture cible → comment organiser la base de données
fondations → comment définir et stocker le marché adressable
identification :
doublons → des identifiants pour vérifier l’unicité des enregistrements d’une table
relations → des identifiants pour lier les tables entre elles
itérations → comment détecter et stocker de nouveaux signaux.
0. Architecture cible

Le marché, constitué d’entreprises et de contacts dans ces entreprises, est au centre car, in fine, c’est aux entreprises qu’on souhaite vendre.
On veut savoir quand et comment les contacter, donc elles doivent occuper une place centrale (dans nos esprits, dans la base de données, partout).
Et parmi les informations qu’on récolte : une variété de signaux d’intent, où chaque type de signal est une espèce de satellite qui gravite autour du marché adressable.
En effet, à l’image du diagramme du dessus, un signal est émis soit par une entreprise, soit par une personne dans l’entreprise.
Donc tout signal est lié à une entreprise ou à un contact.
Je répète :

1. Fondations
Voyons maintenant quoi mettre dans le marché adressable. On peut fixer tout ou partie des critères suivant par exemple :
“toutes les entreprises dans la Drôme, avec entre 50 et 200 employés, dans le bâtiment”
“toutes les entreprises sur lesquelles on a un jour ouvert une opportunité dans le CRM”
“tous les utilisateurs de notre produit, peu importe leur entreprise”.
Ceci dit, je vous recommande fortement de fixer des critères stricts pour ne pas faire déborder votre base de données (quitte à relâcher les contraintes par la suite si la base de données ne déborde pas, mais, au contraire, s’amenuise).
En revanche, en vertu de l’architecture cible du dessus, notez bien ceci : il suffit qu’on détecte un signal d’intent pour que l’entreprise ou le contact qui l’a émis se retrouve en base de données.
Eh oui, certains signaux d’intent n’émanent pas toujours d’une entreprise qu’on a déjà enregistrée (typiquement, les visites d’un site web).
Or, si on veut stocker le signal, on doit enregistrer en même temps l’entreprise émettrice, car tout signal en base est lié à une entreprise ou à un contact (on l’a dit plus haut).
Vous comprendrez donc que les signaux qu’on détecte et la manière dont on les définit a aussi un impact sur l’inflation de notre addressable market :
plus on détecte de signaux, plus on a d’entreprises et contacts en base de données.
Ça peut sembler génial au premier abord, mais c’est à double tranchant car plus la base est remplie :
plus il est difficile et coûteux de maintenir les données à jour
et plus l’attention des business developers est divisée.
À mon avis, il vaut mieux quelques centaines de leads sur lesquels on est parfaitement renseignés que des dizaines de milliers sur lesquels on a détecté un vague signal il y a six mois.

Bref, au lancement du projet, il suffira d’extraire les entreprises et contacts grâce à quelques recherches SalesNav et d’enregistrer les résultats en base.
Ce qui nous mène à la partie suivante.
2. Identification
2. a) Doublons
L’enfer de n’importe quelle base de données, qu’il s’agisse d’un CRM, d’une Google Sheet ou de PostgreSQL, c’est les doublons.
Je sais que le simple fait de lire le mot vous donne déjà des frissons.
Moi aussi.
Et en même temps ça m’énerve.
Car c’est un problème simple à régler.
Vraiment.
IL SUFFIT de définir des identifiants uniques pour tous les enregistrements qu’on stocke en base et de s’y tenir.
C’est tout.
On le fait une fois à la création de la table, et on n’y touche plus.
En revanche, ça a beau être simple, ce n’est pas anodin. Le choix des identifiants est crucial pour l’hygiène de notre base de données.
Par exemple, on évitera à tout prix d’utiliser les noms des entreprises ou des contacts comme identifiants car :
on peut les écrire de quinze manières différentes (Coca, COCA-COLA, Coca Cola Ltd., …)
ils ne sont pas toujours uniques (e.g. “Jean Petit” en France)
ils peuvent changer
lolilol 🌝
De bons identifiants sont les site web pour les entreprises et les emails pour les contacts (même s’ils peuvent changer au fil du temps).
De meilleurs identifiants sont leurs id LinkedIn. Je dirais même plus, si l’essentiel de nos cibles se trouvent sur LinkedIn, il n’y a pas mieux :
ils sont uniques
ne changent pas au gré des rebrandings et mouvements de carrière
sont plutôt simples à retrouver et extraire (à condition d’avoir les bons outils).
Enfin, cela va sans dire, la question des identifiants se pose aussi pour les signaux, puisqu’on veut aussi stocker les signaux en base.
Dès lors, on ajoute un degré de complexité supplémentaire : non seulement il faut leur trouver à tous un identifiant unique pour les dédoublonner, mais, en plus, il faut s’assurer qu’on arrivera à récolter l’identifiant unique de l’entreprise ou du contact auquel les lier.
Example :
On détecte une visite de site web et on veut lier le signal à l’entreprise émettrice (“Terrines de Grands-Mères”). Malheureusement, deux entreprises portent le même nom, l’une dans le Jura et l’autre dans le Gers.
Donc on peut, à la fois faire une croix sur le nom comme identifiant pour dédoublonner les signaux, et à la fois pour les lier aux entreprises.
Vous comprenez le problème.
(on abordera une solution dans la partie 2 de la série).
2. b) Relations
On a touché le sujet du doigt juste au-dessus. Non seulement on veut des identifiants pour ne pas créer de doublons, mais on les veut aussi pour lier nos tables entre elles.
J’en profite pour introduire le bon vocabulaire. On appelle :
clé primaire l’identifiant qui permet de ne pas créer de doublons dans une table — c’est l’identifiant unique de l’enregistrement DANS la table de référence (la table par rapport à laquelle je me positionne — un peu comme un référentiel en physique).
clé étrangère l’identifiant d’un enregistrement ÉTRANGER à la table de référence.
Example : on lie les enregistrements de la table website visit à ceux de la table contacts en utilisant l’identifiant
linkedInUrl
de la table contact, étranger à la table website visits.
Venons-en aux relations entre nos tables : on a déjà dit quinze fois que tout signal était lié à une entreprise ou un contact de la table.
Ok.
Désormais, vous comprenez avec ce que j’ai dit au-dessus que pour chaque signal, il faudra définir une clé étrangère de la table companies ou de la table contacts pour lier le signal à une entreprise ou un contact.
Ok.
Mais quid des contacts et des entreprises entre elles ?
Eh bien, une entreprise peut n’être liée à aucun contact (parce qu’on ne les a pas encore trouvés, parce qu’on n’a pas encore jugé utile de les chercher, parce que ça coûte de l’argent, …).
En revanche, un contact ne peut pas être stocké sans être lié à une entreprise car :
le risque de contacter une entreprise cliente sans s’en apercevoir est trop élevé (si on établit pas ce lien, comment savoir à quelle entreprise le contact appartient ?)
même si on discute avec des humains, à la fin c’est bien une entreprise qui paye (en b2b)
et, de toute façon, quand on a un contact, c’est rare qu’on n’ait pas en plus son entreprise.
C’est précisément ce qu’illustre cette partie du diagramme :

Donc la table contact devra nécessairement contenir un identifiant de la table companies comme clé étrangère.
À nouveau, si vous avez la possibilité de le faire, je vous recommande chaudement d’utiliser les identifiants LinkedIn, à la fois comme clés primaires dans chaque table, mais également comme clés étrangères pour les lier entre elles.
3. Itérations
À chaque fois qu’il y a un nouveau type de signal à détecter, voici les questions à se poser :
Quelle est la source de données pour notre signal d’intent ?
Quel extracteur de données va-t-on utiliser ?
Quelles données l’extracteur va-t-il me retourner ?
Lesquelles pourrais-je utiliser pour construire la clé primaire de mon signal ?
Lesquelles pourrais-je utiliser comme clés étrangères pour lier les signaux aux contacts et entreprises ?
Quel sera le schéma de données (quels champs et de quels types) de mon signal ?
Enfin, comment implémenter le workflow qui me permettra de stocker le signal en base ?
Cette feuille de route a une implication majeure qu’il faut absolument ne pas manquer : chaque type de signal a sa propre table dans la base de données.

Mais pourquoi ? C’est pas un peu over-engineered ?
En fait, vous avez trois options :
Cliquez sur chacun des trois liens du dessus. Vous comprendrez aisément pourquoi la troisième option (i.e. une table par signal) est la meilleure :
on stocke les données avec une granularité maximale
tous les champs sont fortement typés
en limitant les champs intelligemment, on limite de fait les champs vides
et on peut ajouter/supprimer/travailler sur un type de signal sans impacter les autres.
TL;DR
le (total) addressable market est au centre de la base de données, enregistré dans deux tables :
une pour les entreprises
l’autre pour les contacts
il faut le définir avec des critères logiques précis en s’assurant que le nombre d’enregistrements dans la table ne va pas exploser
chaque type de signal d’intent est enregistré dans une table distincte, liée ou bien à la table entreprise, ou bien à la table contact
si un signal est détecté sans que l’entreprise ou le contact soit en base, il faut l’y créer
ce qui signifie que les signaux détectés aussi on un impact sur le nombre d’entreprises et contacts stockés en base
chaque enregistrement de chaque table contient un ou plusieurs identifiants pour :
ne pas créer de doublons dans la table (clés primaires)
lier l’enregistrement à ceux d’autres tables (clés étrangères)
il existe une relation many-to-one entre les contacts et les entreprises :
un contact est lié à une entreprise nécessairement
mais une entreprise est liée à entre 0 et une infinité de contacts
il y a une relation many-to-one entre la table de n’importe quel signal et la table entreprise ou contact (cf. les pointillés verts du diagramme).
Dans le prochain épisode…
Voilà, vous savez tout. La théorie se résume à ces quelques lignes. La semaine prochaine on la mettra en pratique :
j’introduirai Cargo, l’outil qu’on a utilisé avec Bulldozer lors d’une mission ABM
j’expliquerai comment mon collègue a défini l’addressable market
et on déroulera le blueprint sur trois signaux d’intent :
Negative Lemlist Interaction
Big Headcount Variation
Website Visit
Jolis graphes à la clé :

Dopamine shop
À plus ✌️
Bastien.
Reply