Posts tagged "API"

Automatiser le cleaning de son data model Piano Analytics

Si votre entreprise utilise Piano analytics depuis un certain temps, un grand nombre de propriétés personnalisées ont certainement été créées dans votre data model. Et si plusieurs équipes de votre organisation travaillent de manière indépendante sur Piano Analytics ou si un certain turn over existe, il se peut que vous ayez perdu le fil de ce qui est réellement présent ET utile dans votre data model.

Vous pourriez alors vous retrouver avec un data model dégradé comportant des propriétés :

  • En doublon (ayant la même fonction, pas exactement le même nom mais remontant les mêmes valeurs)
  • Faux doublons (ayant la même fonction mais pas exactement le même nom et par exactement les mêmes valeurs)
  • Non exploitées (plus aucune données ne remontent depuis un certain temps)
  • Mono valeurs (remonte systématiquement la même valeur)

Vous pourriez peut-être être étonné du terme « data model dégradé » que j’ai utilisé. En quoi avoir des doublons ou des propriétés sans donnée peut impacter l’exploitation quotidienne des données de votre entreprise ? Laissez-moi vous avancer quelques arguments.

La problématique d’avoir un data model non optimal

Le stock de propriétés personnalisées n’est pas infini

Selon votre compte, vous bénéficiez de 500 à 1 000 propriétés disponibles dans votre data model. Ce chiffre peut vous paraitre inatteignable mais vous seriez surpris de voir à quel point cela peut aller vite, surtout quand plusieurs équipes se partagent l’outil. Cette limite atteinte, vous ne pourrez plus créer de nouvelle propriété sans upgdrader votre compte ou le cleaner. Le compteur de vos propriétés personnalisées est disponible dans votre data model. Pour avoir le bon compte, vous devez appliquer les filtres suivants :

  • Entités : propriétés personnalisées
  • Statuts : validé
  • Visibilité : Visible ET masquée

Compréhension du data model plus complexe

Il faut avoir en tête que chaque propriété créée sera ajoutée dans la liste des éléments disponibles dans Data Query, dans les critères de segmentation ou encore dans le « croiser avec » d’Explorer…Compliqué de s’y retrouver si cette liste comporte des doublons ou des valeurs sans aucune donnée.

Possibles erreurs d’analyses

Si 2 propriétés ont des noms proches mais ne remontent pas exactement la même information, un utilisateur peut potentiellement les confondre et donc analyser des données qui ne concernaient pas sa recherche initiale. Pire, il peut aussi mettre en place une nouvelle règle de processing dans le data model, venant modifier les données de la mauvaise propriété et ainsi impacter irrémédiablement une autre équipe.

Non transversalité des données

Une propriété pouvant être transverse à plusieurs sites, il est dommage de ne pas harmoniser la manière de faire remonter une information. Si vous avez 2 propriétés quasi identiques mais dont une uniquement utilisée sur votre site web et l’autre uniquement sur votre application, il sera beaucoup plus difficile d’analyser ces 2 valeurs au global.

Notre objectif sera donc d’identifier ces propriétés problématiques afin de les désactiver du data model et ainsi regagner en clarté.

Extraction et première analyse de son data model

Comme nous l’avons vu, vous pouvez accéder à l’ensemble de vos propriétés personnalisées dans votre Data model en filtrant sur « Entités » > « Propriétés personnalisées ». Cette vue vous donne une première lecture de vos propriétés mais l’extract proposé dans « Action » > « Extraire Data model » comporte d’avantage d’informations et nous permettra surtout d’ajouter nos propres annotations.

Voici la définition des différents champs présents dans cet extract :

  • propertyKey : clé unique de la propriété, que vous retrouvez notamment dans l’API, ou qui est à utiliser dans votre marquage
  • Type : format déclaré de la propriété (string, integer, date…)
  • Status : La propriété est-elle encore actives (validated) ? Si oui, alors celle-ci est encore susceptible de remonter des données. Si la propriété est inactive (disabled) elle ne peut alors plus remonter de données, même si votre tracking génère encore des events avec celle-ci
  • Hidden : la propriété est-elle disponible dans les analyses Piano Analytics ? Si elle est cachée (hidden=true), alors elle n’apparaitra dans aucun menu. Attention cependant, elle reste disponible pour remonter des données et elle est également requétable dans l’API.
  • custom : La propriété est-elle personnalisée (= créée par vous) ?
  • Name : Quel est son nom visible dans l’interface ?
  • Description : Quel est la définition renseignée avec la propriété au moment de sa déclaration ?
  • usedInImport : la propriété est-elle utilisée pour réaliser des imports de données externes ?
  • Tags : quels sont les mot-clés qui ont été associés à la propriété au moment de sa déclaration ?

Cette liste comportant l’ensemble du data model, nous allons devoir filtrer sur quelques éléments pour isoler nos propriétés personnalisées :

  • S’isoler uniquement sur les propriétés personnalisées, avec « custom » = « true »
  • Garder uniquement celles qui sont encore actives, avec « Statut » = « validated »

J’aurais tendance à vous conseiller de garder les propriétés cachées « hidden »= »true », puisque celles-ci remontent encore de la données et seraient donc aussi potentiellement cleanables.

C’est normalement déjà fait via l’extract, mais je vous conseille de trier le tableau sur la colonne PropertyKey, afin de voir apparaitre les doublons plus facilement.

Automatiser la détection des propriétés problématiques avec Python

Ce fichier nous donne une première base d’information, mais il ne peut en l’état pas nous mettre en évidence les propriétés sans données, ou celles avec des valeurs similaires. Il faudrait donc le faire manuellement, ligne par ligne, avec l’aide de l’interface.

Nous allons donc agrémenter cela à l’aide d’un petit code qui va aller chercher la présence de données sur chaque propriété grâce à l’API Piano Analytics. A partir de là, nous allons pouvoir automatiser un grand nombre de vérifications (doublon, faux-doublon, aucune donnée…)

Création d’un appel API générique

La première étape avec être de créer l’appel API qui nous servira de base pour déterminer :

  • Si une propriété récolte de la donnée (=nombre d’events où la propriété est non nulle) ?
  • Si oui, quel est le nombre de valeurs associées et quelles sont les top valeurs ?
  • Si ces valeurs se retrouvent dans une autre propriété (=synonyme d’un potentiel doublon) ?

Commençons pas créer le template nécessaire dans data Query :

  1. Sélectionnez la propriété personnalisée de votre choix (peu importe laquelle) avec la métrique « évènements ».
  2. Sélectionnez l’ensemble de vos sites de niveaux 1 via la case « tous vos sites » dans le menu de sélection (et oui, une propriété peut potentiellement remonter sur un S1 obscure dont vous n’avez pas connaissance).
  3. Vous allez maintenant sélectionner la période sur laquelle vous souhaitez vérifier la présence de données. A vous de déterminer la période suffisante pour décider de supprimer une propriété qui ne remonte plus de donnée. De mon côté je vais partir sur les 6 derniers mois.
  4. Comme nous voulons vérifier la présence de données, assurez-vous bien que l’option « Affichez les lignes N/A » est bien décochée.

Vous devriez vous retrouver avec une liste des valeurs associées à votre propriété, avec un volume d’évènements par valeur et au total :

Vous pouvez maintenant prendre l’appel l’API GET (« Ouvrir dans » > « Copier l’URL API GET ») de votre template et le mettre de côté. Celui-ci sera encodé, aussi je vous conseille de le désencoder afin de le rendre plus manipulable pour la suite.

Création de la clé API

Pour requêter vos données Piano Analytics depuis l’extérieur de l’interface, vous allez devoir obtenir une clé API. Cette clé est liée à votre compte Piano Analytics, vous n’aurez donc pas la même que votre collègue. Vous aurez également accès au même périmètre que celui disponible dans votre interface (même liste de niveaux 1).

Une fois connecté à votre compte, allez dans votre profil puis dans l’onglet Api Keys.

 Générez une nouvelle clé et conservez bien l’Access key et surtout la secret key, qui ne vous sera plus donnée par la suite.

Configuration du script Python

Pour utiliser ce code, il vous faudra donc une instance Python disponible. Si vous n’en avez pas, vous pouvez utiliser Le service de notebook en ligne de Google.

Vous allez devoir paramétrer quelques variables afin de rendre le code fonctionnel, mais rien d’insurmontable.

headers = {'x-api-key': "secretKey_accessKey"}
url = 'URL API du template créé précédemment'
topValues = 10 #Nombre de top values qui seront présentées
nbSameValues = 2 #Nombre de valeurs similaires pour ajouter un flag entre 2 propriétés
cheminFichierDM = '/file/datamodel.csv'  # Chemin d'accès au data model 
cheminresultats = '/file/' #chemin de dépot des résultats
  1. La variable headers va contenir la concaténation de votre clé secrète avec votre clé publique, séparées par un « _ ».
  2. La variable url contiendra l’URL API que nous avons créée tout à l’heure. Gardez bien en tête que la période sur laquelle les propriétés seront vérifiées est celle que vous avez utilisée dans votre Template (Les 6 derniers mois dans mon exemple)
  3. La variable topValues vous permet de déterminer le nombre de valeurs d’exemples que vous souhaitez voir apparaitre pour chaque propriété dans le fichier final. Si, par exemple, vous placez « 10 », vous aurez donc les 10 valeurs ayant reçues le plus de trafic sur la période choisie
  4. La variable nbSameValues vous permet de déterminer le nombre de valeurs similaires entre 2 propriétés pour leur ajouter un flag de similarité. Si par exemple la propriété Alpha a pour top valeurs [‘A’,’B’,’C’,’D’,’E’] et Beta [‘D’,’E’,’F’,’G’,’H’], et que vous avez nbSameValues=2, alors les 2 variables seront flaggées comme similaires (et donc à vérifier). Mais si vous aviez configuré nbSameValues=3, il n’y aurait pas eu de flag car seules 2 valeurs sont communes aux 2 variables.
  5. La variable cheminFichierDM indique le chemin d’accès du fichier csv extrait depuis votre data model. Ne modifiez pas le fichier extrait, sous peine de voir le script ne pas fonctionner
  6. Finalement la variable cheminresultats sera le dossier dans lequel les fichiers de résultats seront déposés.

Vous n’avez plus qu’à faire tourner le script complet ! Chaque propriété va générer 2 appels API, qui vont ensuite être traités. Il se peut donc que l’exécution dure plusieurs minutes.

Analyse des résultats

Le script va générer 2 fichiers CSV, stats.csv et check_data_DM.csv. Parcourons-les rapidement ensemble.

Comprendre la qualité de votre data model

Le fichier stats.csv vous indique les métriques clés pour comprendre les principaux points d’attention à avoir concernant votre data model.

  1. Custom props : Nombre total de propriétés personnalisées testées dans le script
  2. Nombre de propriétés à vérifier : nombre de propriétés avec au moins un discriminant (points 3 à 6)
  3. Props sans donnée : nombre de propriétés sans aucune donnée sur la période (= aucun event où la propriété testée avait une valeur non nulle)
  4. Props avec doublons : nombre de propriétés ayant un nom identique à une autre, synonyme de potentiels doublons
  5. Props avec valeur unique : nombre de propriétés n’ayant qu’une seule valeur associée
  6. Props avec valeurs similaires : nombre de propriétés ayant au moins X valeurs identiques avec une autre propriété (X étant le nombre défini dans la variable nbSameValues).

Analyser dans le détail les propriétés problématiques

Le fichier check_data_DM.csv reprend les colonnes de départ du data model, filtré sur les propriétés personnalisées et validées. Des nouvelles colonnes ont été ajoutées par le script pour vous aider dans vos travaux :

  1. Statut appel : retourne ‘OK’ si l’appel API a bien pu s’effectuer
  2. Nb résultats : Nombre d’évènements où la propriété avait une valeur non nulle sur la période définie. Vous pouvez filtrer sur « 0 » pour isoler les propriétés sans donnée.
  3. sample : Top valeurs pour la propriété analysée, sous la forme d’une liste
  4. Nombre de valeurs différentes : nombre de valeurs différentes pour la propriété analysée. Vous pouvez filtrer sur « 1 » pour isoler les propriétés qui ne remontent qu’une seule valeur
  5. Doublon ? : retourne la liste des propriétés ayant le même nom (colonne « name ») que la propriété analysée. Filtrez sur une des combinaisons pour analyser ces doublons
  6. Valeurs similaires avec une autre propriété ? : retourne la liste des propriétés ayant au moins X valeurs identiques avec la propriété analysée. Filtrez sur une des combinaisons pour analyser ces propriétés aux valeurs similaires
  7. Colonne avec discriminant(s) : indique True si la propriété possède au moins un des discriminants.

Conclusion

Vous avez maintenant toutes les informations pour déterminer les propriétés à conserver de celles qui doivent être désactivées ou fusionnées.

Une propriété sans discriminant ne veut pas dire qu’elle ne mérite pas votre attention. Elle peut par exemple remonter un volume très faible de trafic (quelques centaines d’events) et donc être synonyme d’une remontée partielle des données. Vous pouvez également constater des valeurs obsolètes dans les valeurs d’exemples données dans la colonne « Sample ».

Finalement, ce cleaning sera inlassablement à refaire sans stratégie de gestion de votre data model. Pensez à mettre en place ou gouvernance solide pour la déclaration et le maintien dans le temps des nouvelles propriétés.

Bonne chance 🙂

Le script complet

import pandas as pd
import requests
import json
import numpy as np
import datetime
import time
pd.options.mode.chained_assignment = None

headers = {'x-api-key': "secretKey_accessKey"}
url = 'URL API du template créé précédemment'
topValues = 10 #Nombre de top values qui seront présentées
nbSameValues = 2 #Nombre de valeurs similaires pour ajouter un flag entre 2 propriétés
cheminFichierDM = '/file/datamodel.csv'  # Chemin d'accès au data model 
cheminresultats = '/file/' #chemin de dépot des résultats

props = pd.read_csv(cheminFichierDM, sep=";", decimal=',', encoding="UTF-8")
props = props[(props['custom'] == True)&(props['status'] =="validated")]
props['Statut appel'] = ''
props['nb resultats'] = ''
props['sample'] = ''
props['nombre de valeurs différentes'] = ''
props['doublon ?'] = ''
props['valeur similaires avec une autre propriété ?'] = ''
urlRootRows = 'https://api.atinternet.io/v3/data/getData?param='
urlRootTotal = 'https://api.atinternet.io/v3/data/getTotal?param='
jsonRowsCall = json.loads(url.split('?param=')[1])
ParamsToRemove = ['sort','max-results','page-num']
jsonTotalCall = json.loads(url.split('?param=')[1])
[jsonTotalCall.pop(x) for x in ParamsToRemove]

for index, row in props.iterrows():
  try:
    jsonRowsCall['columns'] = 
,"m_events"] jsonTotalCall['columns'] =
,"m_events"] call = requests.get(urlRootRows+json.dumps(jsonRowsCall), headers=headers) data = json.loads(call.content) values = [] for i in list(data['DataFeed']['Rows'])[0:topValues]: values.append(i
]) props['sample'][index] = values props['nombre de valeurs différentes'][index] = len(list(data['DataFeed']['Rows'])) call = requests.get(urlRootTotal+json.dumps(jsonTotalCall), headers=headers) data = json.loads(call.content) props['nb resultats'][index] = data['DataFeed']['Rows'][0]["m_events"] props['Statut appel'][index] = 'OK' except: props['Statut appel'][index] = 'KO' for index, row in props.iterrows(): testDoublon = props[props['name'] == row['name']] if len(testDoublon) >1: props['doublon ?'][index] = list(testDoublon['propertyKey']) props['valeur similaires avec une autre propriété ?'][index] = [] for indexbis, rowbis in props.iterrows(): if(index != indexbis): checkSimilars = list(set(row['sample']).intersection(rowbis['sample'])) if len(checkSimilars) >= nbSameValues: props['valeur similaires avec une autre propriété ?'][index].append(rowbis['propertyKey']) props['colonne avec discriminant(s)'] = False props['colonne avec discriminant(s)'][(props['nb resultats'] == 0) | (props['doublon ?'] != '') | (props['nombre de valeurs différentes'] == 1) | (props['valeur similaires avec une autre propriété ?'].astype(str) != '[]')] = True props.to_csv(cheminresultats+'check_data_DM.csv', sep=";", decimal=',',encoding='utf-8-sig') #Enregistrement du tableau final stats = { 'Custom props':len(props), 'Nombre de propriétés à vérifier': len(props[(props['nb resultats'] == 0) | (props['doublon ?'] != '') | (props['nombre de valeurs différentes'] == 1) | (props['valeur similaires avec une autre propriété ?'].astype(str) != '[]')]), 'Props sans donnée': len(props[props['nb resultats'] == 0]), 'Props avec doublons' : len(props[props['doublon ?'] != '']), 'Props avec valeur unique':len(props[props['nombre de valeurs différentes'] == 1]), 'Props avec valeurs similaires': len(props[props['valeur similaires avec une autre propriété ?'].astype(str) != '[]']) } stats = pd.DataFrame({'propriétés':list(stats.values())}, index=list(stats.keys())) stats.to_csv(cheminresultats+'stats.csv', sep=";", decimal=',',encoding='utf-8-sig')

Trust Commander : comment exploiter l’API pour monitorer votre CMP ?

Optimiser le consentement des visiteurs sur nos environnements digitaux est devenu en quelques années un enjeu stratégique majeur pour les sites web et les applications. Les CMP (Consent Management Plateform) se sont développées et ont largement été adoptées par les entreprises afin de fiabiliser la collecte du consentement, maintenir à jour la bannière, ou encore monitorer la performance de celle-ci (taux d’interaction, taux d’optin/d’optout etc.).

C’est justement sur ce dernier point que je souhaite aujourd’hui m’attarder. En effet les CMP proposent des outils de reporting en sein de leur interface afin d’avoir une première lecture de la performance de votre bannière.

Mais il peut arrivez que vous ayez besoin d’extraire ces données, afin d’aller plus loin dans votre analyse ou alors pour injecter la donnée dans un outil tiers (outil de Bi, Data Lake etc.). C’est dans ce contexte que les API proposées par certaines CMP peuvent devenir fort utiles.

Cependant, comme toute API, un travail de préparation préalable est nécessaire afin de comprendre comment celle-ci fonctionne (token, variables, format de retour etc.) et la manière dont nous ait retournée la donnée (imbrications du Json, systèmes d’id, recalcul de la donnée etc.). Je voudrais donc dans cet article vous partager mon retour d’expérience sur l’utilisation de l’API Trust Commander et vous donner un maximum de tips si vous envisagez vous aussi de l’exploiter.

Trust Commander et son outil  Dashboard 

L’API que nous allons donc voir dans cet article est celle de Trust Commander, la CMP proposée par Commanders Act.

L’outil propose par défaut un espace « dashboard », affichant les statistiques principales de différentes bannières créées sur votre compte :

Même si les statistiques données sont claires, vous noterez la présence d’info bulles donnant une définition très précise de chaque chiffre (ex : »Taux d’interaction : Le nombre de visiteurs qui interagissent avec au moins un élément du 1ier écran »). Il existe également une page dédiée dans la documentation en ligne de Commanders Act.

On peut constater 3 filtres :

  • Privacy (choix de la bannière)
  • Appareil (choix des devices)
  • User location (Union Européenne ou hors UE).

S’ajoute à cela un filtre de dates, avec des périodes prédéfinies (aujourd’hui, la semaine dernière, les 30 derniers jours) ou une période custom à sélectionner.

En complément des fonctionnalités préexistantes, l’API s’est avérée utile dans mon cas car j’avais besoin d’afficher des courbes d’évolutions de certains indicateurs, pouvoir les ventiler par device et par bannière, mais surtout d’injecter les données dans un outil tiers.

Fonctionnement de l’API trust Commander

L’API Trust Commander va nous donc permettre d’extraire la donnée de notre CMP à la granularité et la fréquence de notre choix.

Une page de l’aide en ligne lui est dédiée dans Commanders Act.

voyons maintenant ensemble comment l’exploiter !

Récupération de votre Token

Comme on peut le voir dans la documentation, la première étape pour nous sera de récupérer votre Token d’authentification. Sans cela, vous ne pourrez pas requêter l’API.

Pour l’obtenir il faudra contacter votre chargé de compte ou le support Commanders Act (support@commandersact.com). Si ça n’est pas déjà fait, je vous conseille d’effectuer cette demande dès maintenant afin d’obtenir votre token pour la suite de cet article.

Configuration de votre URL racine

L’API Trust Commander se compose d’une URL racine et de paramètres, faisant office de filtres.

La première étape pour nous va donc être de personnaliser l’URL en y ajoutant l’ID de votre compte :

https://api-internal.commander1.com/v2/siteId/privacy/statistics

Si vous ne la connaissez pas, vous pouvez la retrouver directement dans l’URL lorsque vous êtes dans Trust Commander :

Dans mon cas, l’URL racine devient ainsi :

https://api-internal.commander1.com/v2/1234/privacy/statistics

Configuration des filtres

Les filtres disponibles dans l’API Trust Commander sont exactement les mêmes que ceux présents dans l’interface, puisqu’elle requête elle même cette API.

Nous allons donc retrouver les filtres de dates, de devices, de campagnes et de localisation de l’utilisateur (tableau disponible dans la documentation Trust Commander) :

Ainsi, si je souhaite récupérer mes données pour le mois de juillet 2022, uniquement sur Desktop, pour les européens, mon URL sera alors (sans espace) :

https://api-internal.commander1.com/v2/1234/privacy/statistics

?token=123456789

&filter[begin_date]=2022-07-01

&filter[end_date]=2022-07-31

&filter[sup_filters][location][]=1

&filter[sup_filters][device][]=3

Vous pouvez tester votre API directement depuis votre navigateur, ou bien depuis un outil spécialisé. De mon côté j’utilise l’extension Thunder Client disponible dans Visual Studio Code. Pour que votre appel fonctionne correctement, vous devez obtenir une réponse 200 avec un JSON contenant des données :

Il n’y a pas beaucoup plus à dire sur cette API très simple d’utilisation…à part peut-être le multi-filtres !

En effet si vous voulez filtrer sur plusieurs valeurs d’un même critère, par exemple isoler les mobiles et les tablettes pour les devices, vous devrez ajouter autant de fois le paramètre du filtre. Dans mon cas cela sera :

https://api-internal.commander1.com/v2/1234/privacy/statistics

?token=123456789

&filter[begin_date]=2022-07-01

&filter[end_date]=2022-07-31

&filter[sup_filters][location][]=1

&filter[sup_filters][device][]=1

&filter[sup_filters][device][]=2

Dernière astuce, vous pouvez d’abord créer vos filtres dans le dashboard trust Commander, puis récupérer la configuration de l’appel directement dans le network de votre console, en filtrant sur « https://api-internal.commander1.com/v2 » , puis en allant dans payload et en cliquant finalement sur « View decoded » (illustation ci-dessous) :

Structure du Json Trust Commander

Avant de crier victoire et se lancer dans l’industrialisation du requêtage de l’API, il est important de comprendre la structure du JSON qui nous ait retournée. Pour visualiser cela, je vais utiliser l’outil Json Visio (vous pouvez en faire de même dans vos projets). Voici ce que cela donne :

Nous avons donc un objet « data » contenant toutes les données. Celui-ci est constitué d’un tableau d’objets, contenant à chaque fois un type (ici « privacy/statistic » et un id). Chacun de ces objets représente une bannière Trust Commander, et au sein de cet objet, nous retrouvons un certain nombre d’attributs qui sont les données liées à la bannière.

Retrouver la correspondance entre le nom de la bannière et son ID

Comme vous l’aurez compris, nous n’avons pas directement le nom de la bannière, mais son ID.

Pour retrouver à quoi correspond l’ID de votre bannière, vous pouvez aller dans sa zone d’édition et rechercher dans l’URL la valeur présente après « settings » :

Pour récupérer toutes les correspondances en une seule fois, vous pouvez également exécuter ce petit code dans votre console, lorsque vous êtes dans le dashboard Trust Commander :

let table = document
  .querySelector("#statistics_summary")
  .querySelector("thead")
  .querySelectorAll("th");
let finalTable = [];

table.forEach((banner) => {
  if (banner.className) {
    finalTable.push({
      name: banner.innerHTML,
      id: banner.className.split('-')[1]
    });
  }
});

console.table(finalTable);

Voici ce que vous devriez obtenir :

Maintenant que nous avons pu traduire nos ID de bannières avec leur nom, nous pouvons nous attaquer aux données présentes dans ceux-ci !

Comprendre la signification des attributs

Une fois que nous sommes dans les attributs de la bannière, il n’y a plus de difficulté particulière, techniquement parlant. Il suffit maintenant de comprendre les correspondances entre les libellés et les définitions de chaque donnée dans le Dashboard Trust et le nom des attributs dans l’API.

Pour vous aider, voici une petite compilation des correspondances du dashboard et des attributs API (avec les définitions, si elle sont présentes) : Fichier Correspondance.

Comme vous le verrez, 2 typologies d’attributs seront probablement différentes dans votre cas : Les volumes d’optin sur les catégories (ex : « nb_optin_category_1 ») et les vendors (ex : « nb_optin_vendor_3 »).

En effet les catégories et les vendors sont définis par vous lors de l’élaboration de vos bannières. La liste est donc unique à chaque compte. Pour retrouver facilement les correspondances entre les ID et les noms des catégories/vendors, vous pouvez vous rendre dans les pages « Gestions des catégories et Gestion de partenaires de Trust Commander :

Vous avez maintenant normalement tous les éléments pour comprendre au mieux le contenu de ce JSON ! Il nous reste maintenant à requêter cette API de manière plus industrialisée.

Récupération de la granularité de données souhaitée en Python via l’API

Maintenant que nous avons réalisé notre premier appel et avoir compris le contenu de celui-ci, il nous reste à construire le code/process permettant de répondre à notre problématique.

Ce que nous souhaitons récupérer comme données

La première étape est de bien définir ce que nous souhaitons comme résultat final.

Dans mon cas je souhaitais récupérer pour toutes mes bannières l’ensemble des données disponibles dans un appel :

  • Pour chaque jour depuis le 1ier janvier 2022
  • Pour chaque Device
  • Uniquement pour l’Union Européenne

Et pour réaliser cela, je fais le choix pour cet article d’utiliser le langage Python ! Si vous n’avez pas d’instance Python sur votre ordinateur, vous pouvez utiliser Le service de notebook en ligne de Google.

Réaliser un premier appel API en Python (guide pas à pas)

Avant toute chose, entrainons-nous à réaliser un appel simple. Nous allons utiliser cette API, qui est déjà dans le format dont nous aurons besoin :

  • Sur une journée (le 01/07/2022)
  • Sur un device précis
  • Sur les données EU

https://api-internal.commander1.com/v2/1234/privacy/statistics?token=123456789&filter[begin_date]=2022-07-01&filter[end_date]=2022-07-01&filter[sup_filters][location][]=1&filter[sup_filters][device][]=3

Pour ce faire, nous allons utiliser la librairie requests et nous allons créer 2 paramètres :

  • url, qui contiendra la racine de l’URL API
  • params, qui contiendra la query string

On stock finalement le résultat retourné dans la variable ‘data’ via la propriété .content de requests.

Voici le code (j’ai tout de suite appelé l’ensemble des librairies dont nous aurons besoin dans le projet) :

import pandas as pd
import requests
import json
import numpy as np
import datetime
import time

url = "https://api-internal.commander1.com/v2/1234/privacy/statistics"

params = {'token': '123456789',
            'filter[begin_date]': '2022-07-01', 
            'filter[end_date]': '2022-07-01',
            'filter[sup_filters][device][]':3,
            'filter[sup_filters][location][]':1
            }
data = requests.get(url, params=params).content
data

Nous allons maintenant transformer ce texte en JSON via la librairie…json, rentrer dans l’objet ‘data’ (cf partie précédente) et tenter de pousser le résultat dans un dataframe Pandas.

data = requests.get(url, params=params).content
data = json.loads(data)['data']
pd.DataFrame(data)

On commence à avoir un début de quelque chose mais cela ne va pas être encore exploitable. En effet toutes les données qui nous intéressent sont dans l’objet « Attributes » qui est encore sous format Json.

Nous allons donc plutôt créer un tableau, qui ira récupérer l’objet « Attributes » pour chaque valeur de notre tableau data. Nous poussons finalement le résultat dans un nouveau DataFrame :

data = requests.get(url, params=params).content
data = json.loads(data)['data']
listValues = []
for values in data: 
  listValues.append(values['attributes'])
pd.DataFrame(listValues)

Voilà qui est beaucoup mieux ! Nous avons maintenant chaque colonne correspondant à une métrique et chaque ligne correspondant à une bannière…mais laquelle ? L’information de l’ID de bannière de trouvait dans l’objet supérieur à attributes, nous n’avons donc pas cette information dans le tableau. Ajoutons lors de notre boucle une nouvelle propriété « banner id » qui viendra s’ajouter parmi les autres colonnes :

data = requests.get(url, params=params).content
data = json.loads(data)['data']
listValues = []
for values in data: 
  values['attributes']['banner id'] = values['id'] #ajout de l'id de la bannière dans l'objet 'attributes'
  listValues.append(values['attributes'])

table = pd.DataFrame(listValues) # création de la variable table, qui stockera notre dataFrame
table[['banner id','nb_visitors_exposed_to_privacy','nb_banner_views']]

Notre premier tableau étant complet, voyons comment nous pouvons récupérer le reste des données.

Récupérer les données à la granularité souhaitée

Obtenir des données journalières

Nous l’avons vu, l’API trust Commander ne ventile pas les données à la granularité jour. Pour le réaliser, nous allons donc faire un appel pour chaque jour de la période souhaitée, puis reconstituer un tableau de données.

Nous créons une première variable ‘start’ à partir de la date de notre choix via la librairie Datetime. Nous créons une deuxième variable ‘end’ qui correspondra à la date actuelle moins une journée. Nous créons finalement une liste de dates pour chaque journée présente entre ‘start’ et ‘end’.

Libre à vous de personnaliser les dates selon vos besoins !

start = datetime.datetime.strptime("2022-08-15", "%Y-%m-%d") #création de la date de début
end = (datetime.datetime.today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d') # date actuelle moins une journée
date_generated = pd.date_range(start, end) # création d'une liste de dates entre les 2 bornes
date_generated

Il nous reste maintenant à intégrer cette liste dans une série d’appels API via une boucle. Voici le code complet :

import pandas as pd
import requests
import json
import numpy as np
import datetime
import time

url = "https://api-internal.commander1.com/v2/1491/privacy/statistics"
listValues = []

#Définition de la liste de date
start = datetime.datetime.strptime("2022-08-15", "%Y-%m-%d")
end = (datetime.datetime.today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d')
date_generated = pd.date_range(start, end)

#Création d'une boucle à partir de nos dates
for dates in date_generated:
  params = {'token': '123456789',
              'filter[begin_date]': str(dates), #Dynamisation des dates dans l'appel API
              'filter[end_date]': str(dates), #La date de début sera la même que la date de fin
              'filter[sup_filters][device][]':3,
              'filter[sup_filters][location][]':1
              }

  data = requests.get(url, params=params).content
  data = json.loads(data)['data']
  
  for values in data: 
    values['attributes']['banner id'] = values['id']
    values['attributes']['date'] = dates #Ajout de la date parmi les colonnes du tableau final
    listValues.append(values['attributes'])

table = pd.DataFrame(listValues) #compilation de l'ensemble des appels
table[['banner id','date','nb_visitors_exposed_to_privacy','nb_banner_views']]

Obtenir des données pour chaque device

Pour rappel, les devices sont repartis dans 4 id différents (0,1,2,3). Il nous suffit donc de réappliquer la même logique que celle des dates, en incluant une nouvelle série de boucles sur ces ID :

import pandas as pd
import requests
import json
import numpy as np
import datetime
import time

url = "https://api-internal.commander1.com/v2/1491/privacy/statistics"
listValues = []

start = datetime.datetime.strptime("2022-08-15", "%Y-%m-%d")
end = (datetime.datetime.today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d')
date_generated = pd.date_range(start, end)

#Création d'une liste des ID de device
devicesList = [0,1,2,3]

for dates in date_generated:
  for device in devicesList:
    params = {'token': '123456789',
                'filter[begin_date]': str(dates), 
                'filter[end_date]': str(dates), 
                'filter[sup_filters][device][]':device, #Dynamisation du device ID dans l'appel API
                'filter[sup_filters][location][]':1
                }

    data = requests.get(url, params=params).content
    data = json.loads(data)['data']
    
    for values in data: 
      values['attributes']['banner id'] = values['id']
      values['attributes']['date'] = dates 
      values['attributes']['Device'] = device #Ajout du device parmi les colonnes
      listValues.append(values['attributes'])

table = pd.DataFrame(listValues) #compilation de l'ensemble des appels
table[['banner id','date','Device','nb_visitors_exposed_to_privacy','nb_banner_views']]

Renommer les colonnes et enregistrer les données

Comme nous avons déjà récupéré les traductions des colonnes dans un chapitre précédent, nous pouvons les renommer afin de les rendre plus compréhensibles. Je ne vais renommer ici que les colonnes génériques, mais libre à vous de vous occuper également des catégories et des vendors.

Pour cela j’utilise la méthode pd.read_csv() pour récupérer le tableau de correspondance que je vous ai donné tout à l’heure pour renommer mes colonnes via une boucle sur la méthode .rename()

J’enregistre finalement le résultat dans un fichier CSV :

table = pd.DataFrame(listValues) #compilation de l'ensemble des appels

translation = pd.read_csv('/files/trust/translate.csv', sep=";", decimal=',', encoding="latin1") #import de du tableau de correspondance des colonnes
for index, row in translation.iterrows():
      table = table.rename(columns={row['Attribut Json']:row['NOM'].strip()}) #Renommage des colonnes

table.to_csv('/files/trust/trust_practice.csv', sep=";", decimal=',') #Enregistrement du tableau final

Nous avons maintenant notre fichier CSV exploitable dans un outil de dashboarding :

Gestion des mises à jour des données

Nous pourrions très bien ré-exécuter le script sur l’entièreté de la période chaque jour afin de récupérer les données de la veille. Cependant cette méthode n’est pas très optimisée puisque vous allez chaque jour exécuter un très grand nombre de requêtes API pour récupérer uniquement une nouvelle journée de données.

Nous allons donc rédiger une variante de notre premier script, qui lancera uniquement les appels API depuis la dernière mise à jour du fichier puis l’écraser.

Nous allons appliquer la procédure suivante :

  • Import du fichier d’historique
  • Extraction de la date la plus récente présente dans la colonne ‘date’, qui deviendra la date de début des appels
  • Exécution des requêtes API
  • Fusion du tableau des nouvelles données avec le fichier historique

Voici le code adapté :

import pandas as pd
import requests
import json
import numpy as np
import datetime
import time

#Import de l'historique
history = pd.read_csv('/files/trust/trust_practice.csv', sep=";", decimal=',', index_col=[0])

#Extraction de la dernière date connue dans le fichier, qui sera la nouvelle date de début
start = datetime.datetime.strptime(history['date'].max(), "%Y-%m-%d") + datetime.timedelta(days=1)
end = (datetime.datetime.today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d')
date_generated = pd.date_range(start, end)
devicesList = [0,1,2,3]
url = "https://api-internal.commander1.com/v2/1234/privacy/statistics"
listValues = []

#Condition permettant de vérifier si au moins une journée s'est passée depuis la dernière mise à jour
if len(date_generated) > 0:
  for dates in date_generated:
    for device in devicesList:
      params = {'token': '123456789',
                  'filter[begin_date]': str(dates)[0:10], 
                  'filter[end_date]': str(dates)[0:10], 
                  'filter[sup_filters][device][]':device,
                  'filter[sup_filters][location][]':1
                  }

      data = requests.get(url, params=params).content
      data = json.loads(data)['data']
      
      for values in data: 
        values['attributes']['banner id'] = values['id']
        values['attributes']['date'] = dates 
        values['attributes']['Device'] = device 
        listValues.append(values['attributes'])

  table = pd.DataFrame(listValues) 


  translation = pd.read_csv('/files/trust/Correspondance_db_api.csv', sep=";", decimal=',', encoding="latin1") #import de du tableau de correspondance des colonnes
  for index, row in translation.iterrows():
        table = table.rename(columns={row['Attribut Json']:row['NOM'].strip()})

  table = pd.concat([history,table], ignore_index=True) #Fusion de la nouvelle table et de l'historique
  table.to_csv('/files/trust/trust_practice.csv', sep=";", decimal=',') #Enregistrement du tableau final

Afin de ne pas avoir à lancer la mise à jour manuellement, vous pouvez utiliser un scheduler qui le lancera pour vous automatiquement sur un serveur.

Conclusion

Nous avons découvert à travers cet article comment comprendre et exploiter l’API de Trust Commander et obtenir le maximum de granularité dans nos données CMP. J’ai utilisé de mon côté Python mais vous pouvez tout à fait utiliser un autre système (autre langage, solution cloud, outil de BI).