ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Mécanique de l'historique des propriétés HubSpot

Comment fonctionnent les tables d'historique des propriétés HubSpot, leurs limites de rétention, pourquoi les propriétés CALCULATED gonflent les coûts de synchronisation, et comment modéliser les données d'historique sans mauvaises surprises.

Planté
dbtbigquerydata engineeringetldata modeling

HubSpot suit les modifications de propriétés différemment de Salesforce. Là où Salesforce dispose d’un mécanisme FieldHistory unique et de tables d’historique par objet contrôlées via les paramètres de suivi de l’historique des champs, HubSpot maintient des tables d’historique séparées par type d’objet : CONTACT_PROPERTY_HISTORY, DEAL_PROPERTY_HISTORY, COMPANY_PROPERTY_HISTORY, et ainsi de suite. Chaque ligne enregistre une modification de propriété unique : ID d’objet, nom de propriété, ancienne valeur, nouvelle valeur, timestamp.

Deux comportements posent des problèmes dans les pipelines d’entrepôt : les limites de rétention et le type de propriété CALCULATED.

Limites de rétention

L’historique des propriétés HubSpot n’est pas un audit log illimité. Il conserve un nombre fixe de valeurs historiques par propriété par enregistrement :

  • Contacts : jusqu’à 45 valeurs par propriété
  • Autres objets (sociétés, deals, tickets) : jusqu’à 20 valeurs par propriété

Une fois qu’une propriété dépasse sa limite de rétention, les valeurs plus anciennes disparaissent. Si un deal change d’étape 25 fois, vous ne pouvez voir que les 20 plus récentes. Si l’email d’un contact est mis à jour 50 fois (rare mais possible dans des scénarios de nettoyage des données), les 5 premières sont perdues.

Cela a une implication directe sur la façon dont vous utilisez les données d’historique. L’historique des propriétés HubSpot peut répondre à « comment cette propriété a-t-elle changé récemment ? » mais ce n’est pas une piste d’audit fiable pour les enregistrements fortement mutés sur de longues périodes. Si vous avez besoin d’un état ponctuel garanti, les snapshots dbt sur les tables d’objets principales sont plus fiables car vous contrôlez la période de rétention.

L’historique des propriétés est le plus utile pour :

  • L’analyse des transitions d’étapes (combien de deals ont évolué de Proposal à Negotiation le trimestre dernier ?)
  • Les changements récents d’étapes du cycle de vie (qui est devenu MQL dans les 30 derniers jours sur la base de l’historique, pas seulement de l’état actuel ?)
  • Les pistes d’audit de propriétés où vous avez besoin de quelques mois d’historique plutôt que des années

Quand votre analyse nécessite de remonter plus loin dans le temps, ou pour les propriétés qui changent fréquemment, travaillez depuis les tables d’objets principales avec l’historique des snapshots.

Le problème des propriétés CALCULATED

CALCULATED est un type de propriété dans HubSpot pour les champs calculés — valeurs dérivées de formules, de résumés de cumul ou de calculs système. Le problème : les propriétés CALCULATED mettent toujours à jour leurs timestamps de curseur, même quand la valeur calculée n’a pas réellement changé.

Pourquoi cela importe-t-il ? Fivetran et Airbyte utilisent tous les deux une extraction incrémentale basée sur le curseur pour l’historique des propriétés. Le curseur est le timestamp de dernière modification. Quand une propriété CALCULATED met à jour son timestamp sans changer sa valeur, le connecteur la récupère comme un enregistrement modifié et la resynchronise. Vous obtenez une ligne dans CONTACT_PROPERTY_HISTORY avec la même valeur que la ligne précédente — juste un nouveau timestamp.

À grande échelle, cela gonfle significativement les coûts de synchronisation. Un portail HubSpot avec 200K contacts et quelques propriétés CALCULATED peut générer des millions de lignes d’historique fantômes par cycle de synchronisation. Ces lignes ne représentent pas des vrais changements de données ; ce sont des mises à jour fantômes qui consomment vos monthly active rows (si vous êtes sur la tarification MAR de Fivetran) et gonflent vos tables d’historique dans BigQuery.

Comment détecter cela : Comparez les comptages de lignes dans vos tables d’historique au taux réel de modification dans votre portail HubSpot. Si CONTACT_PROPERTY_HISTORY croît bien plus vite que votre comptage de contacts, auditez quelles propriétés sont CALCULATED. Récupérez la liste des propriétés depuis l’API HubSpot :

import hubspot
from hubspot.crm.properties import ApiException
client = hubspot.Client.create(access_token="your_token")
response = client.crm.properties.core_api.get_all(
object_type="contacts"
)
for prop in response.results:
if prop.calculated:
print(prop.name, prop.field_type)

Que faire à ce sujet : Deux options. Premièrement, excluez les propriétés CALCULATED de la synchronisation de l’historique dans la configuration de votre outil d’extraction. Fivetran permet des exclusions au niveau des tables ; Airbyte vous permet de désélectionner des streams. Si vous n’avez pas besoin de l’historique des champs calculés, ne payez pas pour le stocker.

Deuxièmement, si vous avez besoin d’un certain historique de propriétés CALCULATED pour l’analyse, dédupliquez à la couche de modèle de base :

-- base__hubspot__contact_property_history.sql
WITH
source AS (
SELECT
contact_id,
property_name,
property_value AS history__value,
CAST(timestamp AS TIMESTAMP) AS history__changed_at,
-- Déduplication : ne conserver que les lignes où la valeur a vraiment changé
LAG(property_value) OVER (
PARTITION BY contact_id, property_name
ORDER BY timestamp ASC
) AS history__previous_value
FROM {{ source('hubspot', 'contact_property_history') }}
)
SELECT
contact_id,
property_name,
history__value,
history__changed_at
FROM source
WHERE
history__previous_value IS NULL -- premier enregistrement pour cette propriété
OR history__value != history__previous_value -- la valeur a vraiment changé

Cela supprime les valeurs identiques consécutives, ne laissant que les transitions genuines. Cela n’aide pas avec les coûts de synchronisation en amont, mais nettoie les données qui atteignent votre couche mart.

Activation de l’historique dans le package dbt_hubspot

Le package dbt_hubspot traite l’historique des propriétés comme un module optionnel, désactivé par défaut :

vars:
hubspot_contact_property_history_enabled: true
hubspot_deal_property_history_enabled: true

Le package fournit des modèles d’historique avec le problème de lignes dupliquées non résolu. Si vous activez les modules d’historique, appliquez le pattern de déduplication ci-dessus comme post-hook ou en encapsulant les modèles d’historique intermédiaires du package dans votre propre couche.

Considération de coût : CONTACT_PROPERTY_HISTORY en particulier peut devenir votre table la plus grande dans BigQuery, surtout avec les propriétés CALCULATED activées. Avant d’activer l’historique dans le package, vérifiez le nombre de lignes dans votre table d’historique brute et estimez la croissance mensuelle. Pour les grands portails, vous pouvez vouloir activer l’historique uniquement pour des propriétés spécifiques à forte valeur, plutôt que de l’activer globalement.

Utiliser l’historique pour l’analyse des étapes

Le cas d’usage légitime pour l’historique des propriétés de deal est l’analyse des transitions d’étapes quand vous n’avez pas la table DEAL_STAGE dédiée de Fivetran (ou que vous n’utilisez pas Fivetran). Si vous devez reconstruire comment les deals ont évolué à travers les étapes :

-- int__deal_stage_transitions_from_history.sql
SELECT
contact_id AS deal_id,
history__value AS deal__to_stage,
history__changed_at AS deal__stage_changed_at,
LAG(history__value) OVER (
PARTITION BY contact_id
ORDER BY history__changed_at ASC
) AS deal__from_stage,
DATE_DIFF(
history__changed_at,
LAG(history__changed_at) OVER (
PARTITION BY contact_id
ORDER BY history__changed_at ASC
),
DAY
) AS deal__days_in_previous_stage
FROM {{ ref('base__hubspot__deal_property_history') }}
WHERE property_name = 'dealstage'

Si vous utilisez Fivetran, utilisez plutôt la table DEAL_STAGE — elle est plus propre et conçue spécifiquement pour cette analyse. Voir Modélisation des étapes de deal HubSpot pour ce pattern.

Pour le contexte complet du pipeline HubSpot, notamment la façon dont l’historique des propriétés s’inscrit dans la décision de sélection d’outil d’ingestion, voir le guide HubSpot vers BigQuery.