Trackily Docs

Automizer

Un moteur de règles qui surveille tes campagnes en background et déclenche des actions (pause, scale budget, alerte) quand des conditions sont remplies. Plus jamais à mater Voluum à 3h du matin pour pauser une campagne qui leak.

Automizer rules

C'est quoi, l'Automizer

L'Automizer est un rule engine :

  1. Tu définis une règle : "si la campagne 42 dépense plus de 20 USD ET fait moins de 3 conversions sur 24h, alors pause-la et envoie-moi une notif".
  2. Trackily évalue toutes les règles toutes les 60 secondes (la boucle est dans automizer.js:16).
  3. Si toutes les conditions sont vraies (AND logic — voir automizer.js:66), les actions s'exécutent.
  4. Le déclenchement est loggué dans automation_log pour audit.

C'est l'équivalent des "alertes" Voluum / RedTrack, mais avec deux trucs en plus :

  • Tu peux exécuter des actions sur les APIs externes : pause une campagne Meta, change un bid Kadam, baisse le budget Taboola — directement depuis la règle.
  • Les règles sont créables via MCP : tu peux dire à Claude "crée une règle qui pause toute campagne avec un ROI < -40% sur 6h" et l'agent appelle create_automizer_rule pour toi.

L'automizer vs les ops manuelles

Cas Manuel Automizer
Pause d'une campagne qui leak la nuit Tu te lèves à 3h pour la pause Pause auto en 60s, notif Telegram
Scale +20% sur les top performers Tu compares les ROAS à la main chaque matin Règle "ROAS > 2.5 sur 24h → +20% budget Meta"
Détection sources bot-heavy Tu lis les logs fraud chaque jour Règle "bot_rate > 30% sur 6h → pause source"
Tests A/B de creatives Tu suis manuellement et tu coupes les perdants Règle "EPC < 0.10 sur 1000 clicks → pause creative"
Réveil quand un client paie Tu refresh Stripe Règle "conversions > 0 → notif" (gimmick mais ça marche)

L'idée centrale : tout ce que tu fais 2x ou plus par semaine devrait être une règle.

Les briques

Une règle a 4 composants :

{
  "name": "Auto-pause low ROI 6h",
  "campaign_id": 42,                  // ou null pour global
  "conditions": [
    { "metric": "roi", "operator": "<", "value": -40, "window": "6h" },
    { "metric": "clicks", "operator": ">=", "value": 100, "window": "6h" }
  ],
  "actions": [
    { "type": "pause_campaign" },
    { "type": "send_notification", "title": "Campaign paused", "message": "ROI dropped" }
  ],
  "check_interval_minutes": 5,
  "is_active": true
}
  • name — pour t'y retrouver dans la liste
  • campaign_id (optionnel) — scope la règle à une seule campagne. Sans, elle est globale
  • product_id (optionnel, mutex avec campaign_id) — scope à un produit (commerce natif)
  • conditions — un array d'objets. AND entre eux (toutes doivent être vraies)
  • actions — un array d'objets. TOUTES s'exécutent à la suite si les conditions sont met
  • check_interval_minutes — fréquence d'évaluation. Défaut 5. La boucle globale tourne toutes les 60s mais respecte ce throttle par règle.

Comment c'est évalué (boucle 60s)

toutes les 60 secondes:
  rules = SELECT * FROM automation_rules
          WHERE is_active = true
            AND (last_checked IS NULL
                 OR last_checked < NOW() - check_interval_minutes * INTERVAL '1 minute')

  pour chaque rule:
    stats = getStatsForTimeWindow(campaign_id, window)   // ou getProductStatsForTimeWindow
    allMet = true
    pour chaque cond in rule.conditions:
      met = (stats[cond.metric] OPERATOR cond.value)
      si !met: allMet = false; break
    UPDATE last_checked = NOW()
    si allMet:
      pour chaque action in rule.actions:
        executeAction(action)
      INSERT INTO automation_log (rule_id, conditions_met, actions_taken)
      UPDATE last_triggered = NOW(), trigger_count = trigger_count + 1
      dispatch notification 'rule_triggered'

Voir automizer.js:32 pour le code réel.

Une règle qui trigger plusieurs fois d'affilée → vérifie qu'elle a une action qui change l'état (ex : pause_campaign fait que clicks arrête de monter, donc la prochaine évaluation ne re-trigger pas). Sinon ajoute une condition qui devient fausse après l'action.

Ce qui est dans cette section

Page Contenu
Rules Créer une règle (UI + MCP). Schéma JSON complet. 3 exemples worked : auto-pause, auto-scale, anti-fraude.
Conditions Toutes les métriques (clicks, cost, profit, roi, cr, epc, bot_rate…), tous les opérateurs (>, <, =, !=…), toutes les fenêtres ("1h", "6h", "24h", "7d").

Quelques cas réels

"Stop the bleeding" — pause les campagnes qui leak la nuit

{
  "name": "Night safety net",
  "conditions": [
    { "metric": "cost", "operator": ">", "value": 50, "window": "6h" },
    { "metric": "roi", "operator": "<", "value": -50, "window": "6h" }
  ],
  "actions": [{ "type": "pause_campaign" }]
}

"Auto-scale" — augmente le budget des top performers

{
  "name": "Scale winners +20%",
  "campaign_id": 42,
  "conditions": [
    { "metric": "roi", "operator": ">", "value": 80, "window": "24h" },
    { "metric": "conversions", "operator": ">=", "value": 10, "window": "24h" }
  ],
  "actions": [
    { "type": "meta_change_daily_budget", "value": 120 }
  ]
}

value est un budget absolu (ici 120 $/jour), pas un pourcentage : le moteur ne lit ni value_pct ni un sous-objet params (le verdict dirait incomplete).

"Bot heatmap" — pause les sources noyées de bots

{
  "name": "Block bot-heavy traffic",
  "conditions": [
    { "metric": "bot_rate", "operator": ">", "value": 30, "window": "6h" },
    { "metric": "clicks", "operator": ">=", "value": 500, "window": "6h" }
  ],
  "actions": [
    { "type": "pause_campaign" },
    { "type": "send_notification",
      "title": "Bot leak", "message": "Bot rate > 30%" }
  ]
}

Actions disponibles

L'Automizer supporte 37 types d'action, regroupés en familles. Liste exhaustive : ACTIONS dans lib/automizer-lecture.js (le switch d'executeAction, automizer.js, dit la même liste — un test le vérifie). Les réglages d'une action se lisent à plat, à côté de type ({ "type": "pause_offer", "offer_id": 12 }), jamais dans un sous-objet params.

Actions internes Trackily

Type Effet
pause_campaign UPDATE campaigns SET is_active=false
pause_offer UPDATE offers SET status='paused'
change_weight Modifie le poids d'une landing/offer dans un flow
change_bid Update campaigns.cost_value
send_notification Notif via le système global (push, email, Telegram, Slack — selon conf)

Actions API externes (sources de trafic)

Trackily peut appeler les APIs des principales sources de trafic pour pause/scale à leur niveau (pas juste côté tracker) :

Plateforme Actions disponibles
Meta (Facebook/Instagram) meta_pause_campaign, meta_resume_campaign, meta_change_daily_budget, meta_change_lifetime_budget, meta_pause_adset, meta_resume_adset, meta_change_adset_budget
Kadam kadam_pause_campaign, kadam_resume_campaign, kadam_change_bid, kadam_change_budget
PropellerAds propeller_pause_campaign, propeller_resume_campaign, propeller_change_budget, propeller_change_daily_budget, propeller_change_bid
Taboola taboola_pause_campaign, taboola_resume_campaign, taboola_change_budget, taboola_change_daily_budget, taboola_change_bid
TikTok Ads tiktok_pause_campaign, tiktok_resume_campaign, tiktok_change_budget
MGID mgid_pause_campaign, mgid_resume_campaign, mgid_change_budget
ExoClick exoclick_pause_campaign, exoclick_resume_campaign, exoclick_change_budget, exoclick_change_daily_budget, exoclick_change_bid

Pour que ça marche, la campagne (ou le produit) doit être liée à une traffic_sources avec les credentials API valides ET avoir au moins un external_campaign_id mappé. Voir Sources.

Logs et historique

Chaque déclenchement crée une row dans automation_log :

CREATE TABLE automation_log (
  id              SERIAL PRIMARY KEY,
  rule_id         INTEGER REFERENCES automation_rules(id) ON DELETE CASCADE,
  rule_name       TEXT,
  conditions_met  JSONB,         -- snapshot des valeurs au moment du trigger
  actions_taken   JSONB,         -- résultats de chaque action (success/error)
  created_at      TIMESTAMPTZ DEFAULT NOW()
);

Le conditions_met capture les valeurs exactes au moment où la règle a fired :

[
  { "metric": "cost", "operator": ">", "target": 20, "actual": 23.45, "met": true },
  { "metric": "conversions", "operator": "<", "target": 3, "actual": 1, "met": true }
]

Et actions_taken capture le résultat de chaque action :

[
  { "type": "pause_campaign", "campaign_id": 42, "status": "paused" },
  { "type": "send_notification", "status": "notified" }
]

Tu peux consulter l'historique d'une règle dans Automizer → <rule> → Logs, ou via l'API GET /admin/api/rules/:id/logs (les 50 derniers déclenchements).

Santé : « Va s'exécuter ? »

GET /admin/api/rules?detail=1 rend { regles, sante } : chaque règle (les colonnes du GET sans option, inchangées) porte un verdict et une activite, et sante résume la page avec l'état du moteur et une alerte. Sans ?detail=1, la réponse est le tableau d'avant, à l'identique. L'outil MCP list_automizer_rules (et la resource trackily://automizer/rules) rend le même verdict, par la même fonction (lib/automizer-faits.js → lib/automizer-sante.js).

Le verdict passe par les fonctions du moteur (lib/automizer-lecture.js : lecture du JSON, comparaison, prérequis des actions, résolution de la cible et de la source) : l'écran ne peut pas dire « saine » une règle que le moteur refuse. L'ordre est la règle — la première ligne qui s'applique l'emporte :

Code st Quand
en_pause idle is_active n'est pas vrai : le moteur ne la contrôle plus
illisible bad conditions ou actions : JSON invalide, pas une liste, élément qui n'est pas un objet
action_inconnue bad un type absent du moteur
condition_invalide bad métrique non calculée pour la cible (campagne ≠ produit), opérateur hors < > <= >= = !=, valeur non numérique
incomplete bad aucune condition / aucune action, ou action sans ce qu'elle lit (offer_id, value, adset_id, campagne…) — réglages rangés dans params signalés
cible_disparue bad campagne archivée ou introuvable, produit introuvable, offre / flow d'une action archivé ou introuvable
source_non_configuree bad action d'API : pas de source liée, source d'une autre plateforme, aucun ID de campagne externe, clé API absente ou indéchiffrable, réglage manquant (advertiser_id, account_id…)
moteur_arrete bad le moteur ne tourne pas dans ce processus (licence sans Automizer au démarrage)
moteur_en_erreur bad le dernier tour du moteur a échoué
moteur_en_retard warn aucun tour terminé depuis 2,5 × l'intervalle (règle de lib/cron-sante.js)
erreur_evaluation bad la dernière évaluation de cette règle a levé (mémoire du moteur)
derniere_execution_erreur bad toutes les actions du dernier déclenchement ont échoué
derniere_execution_partielle warn une partie seulement a échoué
source_en_echec warn la dernière lecture des dépenses de la source (ads_sync_error) a échoué
moteur_pas_encore_passe info moteur démarré, premier tour pas encore fini
jamais_declenchee info active et saine, ses conditions n'ont jamais été réunies
active ok active et saine

activite : dernier_controle_a, dernier_declenchement_a, declenchements_total, declenchements_24h, declenchements_7j, derniere_action (resultat : ok / partiel / erreur, et chaque action avec son erreur), intervalle_controle_min, erreur_evaluation, et delai_entre_alertes_min: null — il n'existe pas : tant que les conditions tiennent, la règle se redéclenche à chaque contrôle.

Ce que le serveur ne sait pas. Le moteur n'est pas un job de CRON_JOBS : son état (démarré, dernier tour, erreurs d'évaluation) vit dans la mémoire du processus et repart de zéro au redémarrage. Aucune clé API n'est testée (aucun appel réseau) : « configurée » veut dire présente et déchiffrable, pas valide.

Cohabitation cloaking ↔ automizer

Le cloaking décide quel visiteur voit la money page. L'automizer décide si la campagne continue de tourner. Ils sont indépendants :

  • Un visiteur cloaké est compté dans clicks (avec is_bot=true ou similaire) — donc il peut faire monter bot_rate et trigger une règle automizer
  • Une règle automizer qui pause une campagne empêche les nouveaux clicks — donc empêche le cloaking de se déclencher

Combo classique : règle "si bot_rate > 50% sur 1h → pause la campagne" → tu attrapes les attaques bot avant qu'elles ne te coûtent un fortune.

Voir aussi

  • Rules — créer une règle (UI + MCP)
  • Conditions — référence complète des métriques et opérateurs
  • Cloaking — index — le côté server-side de la protection
  • Vue d'ensemble — où l'Automizer s'insère dans la stack
  • MCP — tokens — générer un token avec le scope automizer:write pour piloter via agent