Passer au contenu
megapromotingDiscutons

Expertise · Automatisations marketing

Un environnement de travail dans lequel l’agent qui s’occupe de vos campagnes Google Ads et Meta lit les rapports, propose le changement avec le motif écrit et n’exécute que dans les limites que vous lui avez données.

Le service est une offre, pas une réalisation, et nous le disons en premier : nous n’avons pas aujourd’hui un système qui change des budgets ou des enchères dans Google Ads ou Meta. Nous avons construit et exécuté les pièces à partir desquelles on en fait un — l’envoi du signal de conversion réelle vers Google, un moteur qui achète de la promotion payante avec le dry-run activé par défaut, un registre qui écrit chaque action qui coûte, et un interrupteur qui arrête un orchestrateur sans voie de contournement.

Offre, avec conditions„offer”, nu „delivered”, și motivul se poate verifica în câteva secunde. Am căutat în peste 150 de depozite proprii câmpurile prin care API-urile de reclamă mișcă bani — `budget_micros`, `campaignBudget`, `target_cpa`, `target_roas`, `bid_strategy` — și nu apar nicăieri, nici la Google, nici la Meta. Nu gestionăm azi bugete de reclamă. Ce apare, și se poate deschide fișier cu fișier, sunt piesele care despart o automatizare de un accident: trimiterea conversiilor offline către Google prin Data Manager API, 264 de linii într-un proiect de producție al nostru; un motor de promovare plătită care cumpără boostere, etichete și pachete cu dry-run pornit implicit; un A/B tester bayesian care refuză să declare câștigător sub 100 de afișări per variantă, și orchestratorul de campanii din MEGA CRM cu întrerupător fără `--force`. Serviciul e descris din aceste piese. Nu dintr-un panou care nu există.

Un agent qui s’occupe des campagnes n’est pas un bouton sur lequel il est écrit « optimise ». C’est un programme qui a le droit de lire certains rapports, le droit d’écrire certains champs, et aucun autre droit. La partie difficile n’est pas de proposer un changement — les modèles le font bien et vite. La partie difficile est d’écrire où cela s’arrête, comment il prouve ce qu’il a fait, et ce qui se passe quand il se trompe. C’est de cela qu’il s’agit dans le travail, et c’est là que commence la discussion.

Nous disons dès le début ce que nous n’avons pas, pour que vous ne l’appreniez pas de quelqu’un d’autre. Chez nous, aujourd’hui, il n’exécute pas un système qui augmente un budget dans Google Ads ou qui modifie une enchère dans Meta. Ce qui s’exécute, et peut être montré ligne par ligne, ce sont les mécanismes de sécurité que nous avons écrits pour d’autres automatisations qui dépensent de l’argent réel : dry-run activé par défaut, compteur sur chaque action payante, temporisation en cas d’erreur pour que l’erreur ne se répète pas en boucle, seuil de preuve avant une décision, et un interrupteur qui refuse de démarrer l’orchestrateur.

La pièce que nous avons déjà construite n’est pas un changement de budget, mais un signal — et c’est celle par laquelle nous proposons de commencer. Google apprend de ce que vous lui dites être une conversion. Si vous lui dites « formulaire envoyé », il cherchera des personnes qui envoient des formulaires. Nous avons écrit l’intégration qui lui dit « demande réellement arrivée dans le système du client », avec l’identifiant du clic et des identifiants utilisateur passés par SHA-256, via Data Manager API. Cela peut commencer immédiatement, car c’est du code existant, pas une promesse.

Le reste de l’environnement de travail — la couche qui lit les rapports, la couche qui propose, la couche qui exécute — se construit selon le même schéma que celui que nous avons déjà utilisé là où nous avons déjà dépensé de l’argent par le code. On commence strictement par la lecture, on passe aux propositions sans exécution, et seulement à la fin on ouvre l’exécution, champ par champ, avec une limite écrite sur chacun.

Ce que cela comprend

Le travail, par composantes

Lisez les rapports, pas le tableau de bord

On définit dès le départ ce que l’agent lit et d’où : la dépense par campagne et par groupe d’annonces, les conversions attribuées, le coût par acquisition, la part d’impressions perdue à cause du budget par rapport à celle perdue à cause du classement — deux chiffres différents qui appellent des décisions différentes. La lecture se fait par API, avec un compte de service séparé, et non par captures d’écran de l’interface. La couche de lecture est livrée et démarrée en premier, seule, sans aucune permission d’écriture sur le compte.

Proposez le changement avec la raison écrite à côté

Une proposition n’est pas un chiffre. C’est le champ qui change, l’ancienne valeur, la nouvelle valeur, la fenêtre de données sur laquelle la décision a été prise, et la raison. Les propositions sont rassemblées dans un rapport qu’un humain lit, sous la forme « j’augmenterais le budget journalier de la campagne X de A à B parce que, au cours des N derniers jours, elle a été limitée par le budget dans M% des enchères, à un coût par acquisition inférieur au seuil convenu ». Si la raison ne peut pas être écrite, la proposition n’est pas faite.

Trois seuils : ce qu’il fait seul, ce qu’il demande à un humain, ce qu’il ne fait jamais

Chaque champ entre dans l’une des trois catégories, écrites avant de lancer quoi que ce soit. Seul : changements inférieurs à un pourcentage convenu, à l’intérieur d’un plafond journalier, sur des campagnes marquées comme ouvertes. Avec approbation : tout dépassement du plafond, toute nouvelle campagne, toute nouvelle audience, toute modification d’enchère. Jamais : l’arrêt d’une campagne qu’il n’a pas lancée, la modification du mode de paiement, l’accès aux comptes de facturation. La liste est écrite dans le contrat, pas dans le code, et le code la lit.

Dry-run activé par défaut — le schéma que nous apportons avec nous

Dans notre moteur de promotion payante sur 999.md, la fonction qui décide si de l’argent est dépensé est écrite à l’inverse de la façon habituelle : dry-run est actif si la variable d’environnement n’a pas exactement la valeur `false`. Non définie, vide, `true`, mal écrite — tout cela laisse dry-run activé. C’est un choix délibéré : une erreur de configuration ne peut pas ouvrir le robinet, elle peut seulement le maintenir fermé. La même fonction existe à deux endroits indépendants, le moteur de promotion et l’exécuteur de republication.

Chaque action qui coûte est consignée dans un registre

Dans le système de promotion, toute exécution entre dans un tableau `agent_costs` avec l’annonce, l’utilisateur, le type d’action, le montant en lei, si elle a réussi, la réponse brute du fournisseur et un marqueur `dry_run`. L’écriture se fait dans la même transaction que la mise à jour de la programmation, donc il ne peut pas y avoir de dépense sans trace ni de trace sans dépense. Quand c’est dry-run, le montant enregistré est zéro, mais la ligne existe — on voit exactement ce qui se serait passé.

Le signal de conversion réelle — la pièce qui existe déjà

Lorsqu’une personne arrive depuis un clic payant et soumet une demande, le signal n’est envoyé à Google qu’après l’entrée de la demande dans le système du client, et non au moment de l’appui sur le bouton. L’intégration utilise `https://datamanager.googleapis.com/v1/events:ingest`, envoie l’identifiant du clic, le moment, la valeur et la devise, ainsi que des identifiants d’utilisateur passés par SHA-256 — l’adresse normalisée en minuscules, le téléphone ramené au format international. Sans l’identifiant du clic, l’envoi s’arrête de lui-même et est marqué comme sauté, car il ne serait pas attribuable.

Le consentement se place avant les étiquettes, pas après

Consent Mode v2 est initialisé avec tous les objectifs de marketing et d’analyse sur `denied`, avant qu’un script Google ne démarre, avec une fenêtre d’attente de 500 ms pour la mise à jour. Le passage à `granted` ne se fait qu’à l’interaction de la personne avec la bannière, sans rechargement de la page. Le stockage fonctionnel et celui de sécurité restent activés, car sans eux la page ne fonctionne pas. C’est écrit une fois et s’exécute à chaque visite.

La décision entre deux variantes se prend sur la preuve, pas sur l’impression

Le testeur A/B que nous avons construit modélise chaque variante comme Beta-Binomial avec un prior uniforme et estime la probabilité que l’une soit meilleure au moyen de 10.000 échantillons Monte Carlo. Il ne déclare pas de gagnant en dessous de 100 affichages par variante et en dessous d’une probabilité de 0,95. Si, au bout de 168 heures, rien n’a été décidé, il clôt l’expérience et indique qu’elle a expiré, au lieu de nommer un gagnant qu’il ne peut pas étayer.

Un interrupteur qu’on ne peut pas contourner

L’orchestrateur de campagnes de notre système interne vérifie une variable d’environnement avant toute chose. Si elle est définie, il refuse de démarrer — il n’existe pas de `--force`, aucun argument ne peut passer outre. Il a été ajouté après un incident réel d’envois en double, pas pour la décoration. Le même schéma est appliqué ici : un commutateur au niveau du compte qui arrête toutes les écritures, tout en laissant la lecture et le reporting continuer.

À quoi cela ressemble

Le parcours, étape par étape.

01

L’inventaire des comptes et des droits

Les comptes publicitaires sont listés, qui a accès aujourd’hui et avec quel rôle, quelles conversions sont définies et lesquelles sont en fait des doublons du même événement. Les trois listes de champs sont établies — seul, avec approbation, jamais. Nous livrons : l’inventaire rédigé, la liste des conversions avec ce que chacune mesure réellement, et l’accord sur les trois listes.

02

La couche de lecture, lancée seule

La lecture est connectée via API avec un compte qui n’a pas de droit d’écriture, et le rapport quotidien est lancé. Rien ne change dans les comptes à cette étape — on ne voit que ce que voit l’agent. C’est le moment où apparaissent les conversions qui comptaient mal, les campagnes limitées par le budget sans que personne le sache, et les audiences qui se chevauchent. Nous livrons : le rapport quotidien et la liste de ce que nous avons trouvé en lisant.

03

Le signal de conversion réelle

L’identifiant du clic est capturé sur la page d’atterrissage, il est lié à la demande dans votre système et envoyé à Google seulement lorsque la demande est confirmée en aval, et non au moment de l’appui sur le bouton. La reprise automatique des envois échoués est activée, dans la fenêtre de 90 jours. Nous livrons : l’intégration fonctionnelle, un mode de vérification qui envoie sans enregistrer, et le journal avec ce qui est parti et ce qui a été sauté et pourquoi.

04

La couche de propositions, sans exécution

L’agent commence à écrire des propositions : champ, ancienne valeur, nouvelle valeur, motif, fenêtre de données. Rien n’est exécuté. Cela tourne ainsi jusqu’à ce que les propositions deviennent ennuyeuses — c’est-à-dire jusqu’à ce que la personne qui les lit aurait de toute façon cliqué « oui » sur presque tout. Nous livrons : le flux de propositions, avec tout ce qui a été proposé et ce que vous avez approuvé ou refusé, afin de voir où cela se trompe.

05

L’ouverture de l’exécution, champ par champ

L’exécution est ouverte pour le premier champ de la liste « seul », avec dry-run activé par défaut et avec un plafond quotidien. On vérifie dans le registre que ce qui a été écrit est ce qui a été proposé. Puis le deuxième champ. Nous livrons : le registre des actions, le commutateur qui arrête toutes les écritures en laissant la lecture activée, et la procédure écrite pour ce qu’il faut faire lorsque l’agent s’est trompé.

Traseul unei decizii1citire prin API cucont fără drept descriere2propunere cu câmp,valoare veche,valoare nouă și motiv3filtrul celor treiliste (singur / cuaprobare / niciodată)4execuție cu dry-runpornit implicit șiplafon zilnic5rând în registrul decosturi, scris înaceeași tranzacțieComutatorul de oprire taie execuția și lasă citirea pornită.
Traseul unei decizii

Les données

Ce que nous touchons, où elles sont et combien de temps elles restent

Les questions que pose toute personne ayant un délégué à la protection des données — posées ici avant qu'il ne les pose.

Quelles données il touche
Rapports de campagne, groupe d’annonces et mot-clé lus via l’API. L’identifiant de clic de l’annonce, capturé depuis l’adresse de la page d’atterrissage et conservé sur la requête client. Événements de conversion avec moment, valeur et devise. À la demande explicite, l’adresse e-mail et le téléphone de la personne ayant converti, mais uniquement sous forme de résumé cryptographique.
Ce qui part vers Google et sous quelle forme
L’identifiant de clic part en clair — c’est bien cela, un identifiant de clic. L’e-mail et le téléphone partent uniquement en SHA-256, calculé localement avant l’envoi : l’e-mail nettoyé des espaces et passé en minuscules, le téléphone ramené au format international. L’adresse postale n’est pas envoyée du tout, parce que le schéma Google l’exige complète avec code postal et code de région, et le code postal n’est pas cohérent dans les données réelles — la raison est écrite dans le code, pas supposée.
Où elles sont et qui les voit
Les données de campagne et les événements restent dans la base de votre projet, sur l’infrastructure convenue. Les identifiants des comptes publicitaires restent dans un fichier d’environnement lu par le service système, pas dans le code et pas dans le dépôt des sources. Le jeton d’accès est conservé en mémoire au maximum 55 minutes, même si le fournisseur le donne comme valable 3 600 secondes — la marge est intentionnelle, afin de ne jamais en utiliser un expiré.
Pendant combien de temps un événement peut encore être envoyé
La fenêtre pratique est de 90 jours à partir du moment de la conversion — c’est ce que Google accepte pour les conversions hors ligne. La nouvelle tentative pour les envois échoués fonctionne exactement dans cette fenêtre, par lots, avec un maximum de cinq tentatives par requête. Après cinq tentatives, la requête est laissée tranquille et reste marquée comme non envoyée, au lieu d’être réessayée à l’infini.
Ce que nous ne faisons pas avec les données
Nous ne construisons pas d’audience à partir de vos listes de clients sans base légale écrite et sans que cela apparaisse dans l’information vue par la personne. Nous ne transférons pas de données entre les comptes de deux clients différents. Nous ne conservons pas de copies des rapports de campagne en dehors du système convenu. Le registre des traitements est complété avant le premier envoi, pas après.

Un cas

Une campagne qui payait pour des formulaires, pas pour des demandes

La situation

Une plateforme de Chișinău qui reçoit des demandes en ligne achetait du trafic de recherche. La conversion définie dans le compte publicitaire était « formulaire envoyé ». L’algorithme d’enchère faisait exactement ce qu’on lui demandait : il apportait des personnes qui envoient des formulaires. Combien d’entre elles devenaient de vraies demandes, plus loin dans la chaîne, ne remontait jamais jusqu’à la plateforme publicitaire.

Ce que nous avons construit

Nous avons déplacé le moment de conversion plus loin dans la chaîne. L’identifiant de clic est capturé sur la page d’atterrissage et conservé sur la requête. La requête part ensuite vers le système en aval ; si celui-ci renvoie son propre identifiant — c’est-à-dire qu’il est réellement entré — alors seulement l’événement part vers Google, via l’API Data Manager, avec le moment, la valeur, la devise et les identifiants utilisateur passés par SHA-256. Sans identifiant de clic, l’envoi s’arrête de lui-même et est marqué comme sauté. Nous avons ajouté un job de nouvelle tentative qui cherche les requêtes avec identifiant de clic et sans marque d’envoi, sur les 90 derniers jours, par lots de 50, avec au plus cinq tentatives.

Ce qui en est sorti

Le signal que reçoit la plateforme publicitaire décrit désormais les demandes qui arrivent à destination, pas les clics sur les boutons. Toutes les opérations sont inertes si l’intégration n’est pas configurée ou est arrêtée — la fonction vérifie les sept identifiants avant toute chose, et renvoie « ignoré » s’il en manque un. Les erreurs sont journalisées, mais ne se propagent pas : si Google ne répond pas, la demande du client continue sans être touchée.

Ce que le cas ne dit pas

Ceci est une intégration de signal, pas de gestion de campagne. Elle ne modifie ni budget ni enchère. L’effet sur le coût par acquisition n’a pas été mesuré par nous et nous ne le publions pas — dans le code, il existe une attente écrite par l’auteur, pas une mesure, et entre les deux se trouve toute la différence.

Questions

Ce que les gens nous demandent avant d'appeler

Qui porte la responsabilité lorsque l’agent augmente un budget et que la dépense monte ?

Vous. Et c’est pourquoi l’environnement est construit pour que vous puissiez porter la responsabilité en connaissance de cause, et non pour vous surprendre. Concrètement : l’agent n’a aucune permission d’écriture qu’une personne ne lui ait donnée nommément, par écrit, champ par champ ; chaque champ ouvert a un plafond au-delà duquel la proposition part en approbation humaine ; chaque action exécutée est inscrite dans un registre avec l’ancienne valeur, la nouvelle valeur et le motif, dans la même transaction que l’exécution ; et il existe un commutateur qui arrête toutes les écritures sans arrêter la lecture. Nous répondons de ce que nous avons construit — à savoir que les limites que vous avez écrites sont respectées par le code, que le registre est complet, que l’arrêt fonctionne. Nous ne répondons pas du résultat commercial d’un changement que vous avez approuvé, pas plus qu’une agence qui appuie sur le bouton manuel. Si quelqu’un vous promet autre chose, demandez-lui ce qui est écrit dans le contrat au chapitre de la limitation de responsabilité.

Avez-vous aujourd’hui un système qui gère des campagnes Google Ads ou Meta ?

Non. Nulle part dans notre code n’apparaît un champ par lequel on modifie un budget, une enchère ou une stratégie d’enchères chez Google ou Meta. Nous avons vérifié en recherchant exactement ces noms de champs dans tous les dépôts. Ce que nous avons, c’est l’envoi des conversions vers Google, un moteur qui achète de la promotion payante sur une autre plateforme, et les mécanismes de sécurité qui les entourent. Le service se construit à partir de là, et il est marqué comme offre précisément pour éviter toute confusion.

Alors qu’avez-vous déjà construit et qui dépense de l’argent réel ?

Notre moteur de promotion payante d’une plateforme d’annonces classées de Moldavie. Il pose des étiquettes payantes, lance des boosters avec une limite quotidienne et un prix par clic, active des packs et republie des annonces après un intervalle calculé à partir de la vitesse réelle de la catégorie. Il refuse de lancer un booster dont la limite quotidienne n’est pas supérieure au prix par clic — une petite vérification, mais exactement le type de vérification qui manque d’habitude. Chaque action passe par la vérification de dry-run avant tout appel qui coûte.

Qu’est-ce qu’il peut modifier seul et qu’est-ce qui exige une approbation ?

Cela se décide ensemble, à l’avance, et c’est écrit. Notre point de départ dans la discussion : seul — des ajustements inférieurs à un pourcentage convenu du budget quotidien, à l’intérieur d’un plafond quotidien absolu, sur les campagnes que vous avez marquées comme ouvertes ; avec approbation — tout dépassement du plafond, les nouvelles campagnes, les nouveaux publics, tout toucher aux enchères ; jamais — l’arrêt des campagnes lancées par quelqu’un d’autre, les méthodes de paiement, les comptes de facturation. Si vous voulez tout soumettre à approbation au début, c’est un choix valide et nous le préférons.

Comment l’agent sait-il qu’une conversion est réelle et non un formulaire vide ?

Parce que le signal ne part pas à l’appui du bouton. Il ne part que lorsque la demande est confirmée en aval, dans le système qui compte pour vous — un identifiant de demande renvoyé par le CRM ou par le partenaire. Jusqu’à ce moment-là, rien ne s’est produit qui mérite d’être appelé conversion. La différence n’est pas cosmétique : l’algorithme d’enchères de Google apprend de ce que vous lui envoyez, donc si vous lui envoyez des formulaires, il vous apportera des personnes qui remplissent des formulaires.

Qu’advient-il des données personnelles de ceux qui convertissent ?

L’e-mail et le téléphone ne partent que sous forme de résumé cryptographique SHA-256, calculé localement avant l’envoi, avec normalisation — e-mail sans espaces et en minuscules, téléphone ramené au format international. L’adresse postale n’est pas envoyée du tout. Rien ne part avant que la personne ait accepté la finalité marketing dans la bannière, car Consent Mode démarre entièrement sur `denied`. La base légale et l’information sont rédigées avant le premier envoi, pas après la première question de quelqu’un.

Que se passe-t-il si l’appel à la plateforme de publicité échoue à mi-chemin ?

L’échec est enregistré avec la réponse brute, et l’action est reportée — dans notre exécuteur de republication, avec au maximum le plus grand entre le refroidissement configuré et cinq minutes, explicitement pour qu’une erreur ne se transforme pas en boucle d’appels. Les envois de conversions échoués sont relancés par un job séparé, par lots de 50, avec au plus cinq tentatives par demande, dans la fenêtre de 90 jours. Après la cinquième tentative, cela s’arrête et reste marqué comme non envoyé, pour que cela se voie, et non pour disparaître.

Comment l’arrêtez-vous, complètement et rapidement ?

L’interrupteur d’écriture. La lecture et le reporting continuent, l’exécution s’arrête. Dans nos systèmes existants, cela est implémenté de deux façons, toutes deux vérifiables : une variable d’environnement qui doit avoir exactement la valeur `false` pour que de l’argent soit dépensé — tout autre chose maintient le robinet fermé — et un interrupteur sur l’orchestrateur de campagnes qui refuse le démarrage et n’a pas de `--force`. Nous ne dépendons pas d’un bouton dans une interface qui peut ne pas se charger.

Me garantissez-vous une baisse du coût par acquisition ?

Non, et il vaut la peine d’expliquer pourquoi, car dans notre code il existe exactement un tel chiffre. Dans le commentaire en tête de l’intégration des conversions, il est écrit une attente — de combien le coût par acquisition pourrait baisser et de combien la part d’impressions pourrait augmenter. C’est une attente écrite par celui qui l’a construite, pas une mesure, et c’est pourquoi vous ne la trouverez nulle part sur ce site comme résultat. Ce que nous pouvons vous promettre, c’est que la mesure pourra être faite : avec des conversions qui veulent dire quelque chose et avec un registre de chaque changement, la comparaison avant-après devient possible. Sans cela, non.

Sur quoi reposent les affirmations ci-dessus (20 sources)

20 d'entre elles sont du code et des fichiers de nos dépôts. Nous n'en publions ni le nom ni la ligne : réunies sur une seule page, elles décriraient trop précisément comment sont construits des systèmes qui ne sont pas seulement les nôtres. Nous les parcourons avec vous, dans le dépôt, sur demande — la vérification reste possible, elle se fait simplement lors d'un échange.

Qu'est-ce que vous voudriez voir mieux fonctionner ?

Racontez-nous votre processus. Ensemble, nous décidons ce qui vaut la peine d'être construit, ce que nous pouvons connecter et comment nous vérifions le résultat.

Discutons