13 min de lectureFonctionnalités

Suivi des conversions côté serveur via des liens courts

L'architecture pour transmettre les conversions à Meta CAPI, GA4 Measurement Protocol et TikTok Events côté serveur - propagation du click_id, déduplication, hachage et sémantique de retry

Ana Kowalska
Marketing solutions engineering
Server-side conversion forwarding diagram: short link captures click_id, order webhook triggers fan-out to Meta CAPI / GA4 MP / TikTok Events with SHA-256 hashed identifiers and dedup event_id

Le pixel navigateur est la partie de l'attribution qui casse en premier. L'Intelligent Tracking Prevention d'Apple plafonne les cookies tiers et dégrade le referrer ; les bloqueurs de publicité retirent l'appel réseau pixel avant qu'il ne quitte la page ; l'App Tracking Transparency d'iOS 14.5 a coupé la qualité du signal Meta sur le trafic iPhone à un point tel que Meta eux-mêmes traitent désormais le pixel navigateur comme une sauvegarde.

Le suivi des conversions côté serveur est la réponse sur laquelle tout le monde est d'accord. L'implémentation est ce que les gens se trompent. Ce billet parcourt l'architecture telle qu'elle s'établit lorsqu'un raccourcisseur d'URL possède le click_id - ce que fait le raccourcisseur, ce que fait votre back-end, ce qu'attendent les plateformes publicitaires de leur côté, et la forme de déduplication qui vous empêche de double-compter quand à la fois le navigateur et le serveur émettent.

Les trois plateformes vers lesquelles la plupart des équipes transmettent : Meta CAPI, GA4 Measurement Protocol, TikTok Events API. Mixpanel, Klaviyo et Pinterest acceptent la même forme avec des noms de champs spécifiques au fournisseur. Je serai précise sur Meta et GA4 parce qu'ils pilotent la majorité du budget ; les autres suivent le même template.

Pourquoi côté serveur#

La version courte : le navigateur n'est plus une source de signal fiable. La version plus longue vaut la peine d'être comprise parce qu'elle façonne la façon dont vous configurez la déduplication.

Trois choses dégradent les conversions côté navigateur :

Partitionnement des cookies et plafonds de durée de vie. L'ITP de Safari partitionne les cookies par site de premier niveau et plafonne les cookies de première partie définis par script à 7 jours (24 heures après qu'un tracker cross-site connu est détecté). La Total Cookie Protection de Firefox fait un partitionnement similaire. Brave et la cohorte des extensions de confidentialité vont plus loin. Le flux d'attribution par cookie de première partie qui fonctionnait en 2018 ne fonctionne pas en 2026.

Bloqueurs de publicité. uBlock Origin, AdBlock Plus, Pi-hole, NextDNS et les bloqueurs au niveau réseau livrent des règles par défaut pour connect.facebook.net, googletagmanager.com, analytics.tiktok.com et le reste de la surface des tags marketing. Le pixel ne se déclenche jamais ; la conversion ne s'enregistre jamais.

App Tracking Transparency d'iOS et les changements de tracking de liens d'iOS 17. ATT a coupé la qualité du signal Meta. La Link Tracking Protection d'iOS 17 a étendu ceci aux paramètres de requête en navigation privée et dans Mail, retirant fbclid, gclid et une liste d'autres avant que le lien ne soit ouvert.

L'effet cumulatif sur une boutique Shopify typique avec trafic majoritairement iOS : 25 à 40 % des conversions sont manquées par les pixels côté navigateur. Le chiffre exact dépend de votre mix de trafic ; les marques beauté et habillement à dominance iOS sont dans le haut de la fourchette. L'arithmétique du revenu récupéré est ce qui justifie le travail d'ingénierie - pour une boutique faisant 10 M€/an de revenu avec un écart d'attribution pixel de 30 %, récupérer même la moitié de cet écart représente 1,5 M€ de revenu attribuable acheminé vers les plateformes qui l'ont généré.

Le transfert de conversion côté serveur ferme la majeure partie du fossé. Il ne le ferme pas tout - il y a des conversions où le click_id n'a jamais été capturé (organique, direct, recherche de marque) qu'aucune quantité de CAPI ne récupérera - mais il ferme le fossé qui provenait du blocage côté navigateur.

L'architecture#

Le flux de données comporte quatre étapes : pub → lien court → site → transfert côté serveur.

Plateforme publicitaire → lien court. La destination de la créa Meta ou Google Ads est un lien court. L'utilisateur clique ; le handler edge du lien court capture l'événement de clic et redirige vers l'URL de destination avec un click_id ajouté.

Lien court → site. L'URL de destination a ?elido_click=<id> ajouté (configurable par workspace). Le gestionnaire de tags du site ou le code du thème le lit et l'écrit dans un cookie de première partie ou, plus important, dans l'attribut custom du panier ou de la commande.

Site → commande. Quand l'utilisateur finalise une commande (panier Shopify soumis, commande WooCommerce créée, panier headless converti), le click_id est sur les attributs/métadonnées de l'enregistrement de commande. C'est le point de transfert durable - une fois que le click_id est sur la commande, il n'est plus soumis à l'expiration des cookies ou à la durée de vie de la session navigateur.

Commande → transfert côté serveur. Le webhook order-paid se déclenche depuis votre plateforme commerce. Votre back-end (ou Elido, si vous lui avez délégué) lit le click_id, recherche les identifiants de transfert de conversion et POSTe la conversion à chaque plateforme publicitaire connectée. Les plateformes reçoivent la conversion et créditent la campagne originatrice.

Le rôle du raccourcisseur est le click_id à l'étape 2 plus l'orchestration à l'étape 4. Le premier est direct ; le second est là où l'intégration gagne sa pierre.

Pipeline en quatre étapes : le clic de la plateforme publicitaire passe par le lien court qui capture le click_id, puis vers le site, dans l'enregistrement de commande, et le webhook order-paid déclenche un fan-out côté serveur vers Meta CAPI, GA4 MP et TikTok Events

Déduplication : ce dont personne ne parle jusqu'à la production#

Le grand incident de production que je vois le plus souvent est le double-comptage. Le pixel côté navigateur est toujours sur la page (l'équipe ne l'a pas désactivé parce qu'elle voulait un fallback navigateur pour le trafic non-Safari), et le transfert côté serveur se déclenche aussi. Meta ingère les deux événements. La conversion est double-comptée, l'allocateur de budget sur-pompe, la revue de budget de la campagne suivante remarque « attendez, pourquoi notre ROAS reporté est 3× le revenu ? ».

La correction est l'identifiant de déduplication. Meta CAPI accepte un event_id. GA4 Measurement Protocol accepte un client_id et un transaction_id. TikTok Events accepte un event_id. Si à la fois le navigateur et le serveur envoient le même événement avec le même dedup ID, la plateforme en crédite un et ignore le second.

Le dedup ID doit avoir la même valeur des deux côtés. L'ID de commande fonctionne pour les événements d'achat - à la fois le pixel côté navigateur et le transfert côté serveur le voient. Le click_id fonctionne pour les événements en amont (lead, add-to-cart, view-content) où la commande n'existe pas encore.

La documentation de déduplication de Meta parcourt la fenêtre de correspondance : les événements reçus dans les 48 heures l'un de l'autre avec le même event_id sont traités comme des doublons. La déduplication GA4 basée sur client_id est similaire en principe bien que moins documentée.

La règle opérationnelle : chaque conversion côté serveur doit porter le dedup ID, et le dedup ID doit être le même que celui que le pixel côté navigateur a émis. Sauter ceci est la différence entre une intégration CAPI qui fonctionne et une qui gonfle silencieusement vos chiffres rapportés pendant trois mois jusqu'à ce que quelqu'un le remarque.

Flux de déduplication où le pixel navigateur et le transfert serveur émettent tous deux event_id order-001847 ; le comparateur de la plateforme crédite un événement dans la fenêtre de 48 heures et supprime le doublon, tandis que des identifiants non correspondants provoquent un double-comptage

Exigences de hachage#

À la fois Meta CAPI et TikTok Events exigent que les identifiants email et téléphone soient hachés SHA-256 avant transmission. GA4 ne l'exige pas strictement mais l'accepte. Le hachage porte sur les identifiants client - em (email), ph (téléphone), fn (prénom), ln (nom), ge (genre), db (date de naissance), ct (ville), st (état), zp (code postal), country (pays) - pas sur les métadonnées de l'événement.

Deux pièges. Premièrement, le format doit être normalisé avant le hachage - lowercase, trimmed, indicatif pays retiré du téléphone, tirets supprimés. Hacher [email protected] produit une valeur différente de hacher [email protected] ; les plateformes attendent la seconde. La page des exigences de paramètres de Meta liste les règles de normalisation par champ.

Deuxièmement, le hash doit être en hex minuscule sans espaces. SHA256("[email protected]") produit a3b6... ; l'API attend a3b6..., pas A3B6... et pas \xa3\xb6.... La plupart des SDKs de langage retournent du hex majuscule par défaut ; vous devez mettre le résultat en minuscule.

Si vous routez via le endpoint POST /v1/conversions d'Elido, le hachage est géré côté plateforme - vous POSTez l'email/téléphone brut, Elido fait la normalisation et le hachage selon l'exigence de chaque plateforme, et transmet. L'avantage est un seul ensemble de règles de normalisation pour votre back-end à maintenir au lieu de trois. Le coût est que vous faites confiance à Elido avec les PII brutes au moment du transfert ; la requête est chiffrée en transit et non persistée côté serveur, mais le modèle de confiance vaut la peine d'être compris avant de la câbler.

Un POST Meta CAPI travaillé#

Ce que la plateforme veut réellement. Le endpoint est POST https://graph.facebook.com/v21.0/{pixel_id}/events. Le body est JSON.

{
  "data": [
    {
      "event_name": "Purchase",
      "event_time": 1716480000,
      "event_id": "order-acme-2026-05-23-001847",
      "action_source": "website",
      "event_source_url": "https://acme.example/checkout/thanks?order=001847",
      "user_data": {
        "em": ["a3b6...sha256 of email"],
        "ph": ["c4d7...sha256 of phone"],
        "client_user_agent": "Mozilla/5.0 ...",
        "client_ip_address": "203.0.113.42",
        "fbc": "fb.1.1716470000.AbCdEf",
        "fbp": "fb.1.1716470000.987654321"
      },
      "custom_data": {
        "currency": "EUR",
        "value": 89.5,
        "content_ids": ["sku-spring-jeans-32-blue"],
        "content_type": "product",
        "num_items": 1
      }
    }
  ],
  "test_event_code": "TEST12345",
  "access_token": "EAAxxxxxxx"
}

Trois choses qui valent d'être notées :

L'event_id est la clé de déduplication. Mettez-le à votre ID de commande ; le pixel Purchase côté navigateur met la même valeur. Meta déduplique dans la fenêtre de correspondance de 48 heures.

fbc et fbp sont les identifiants cookie de Meta. fbc est l'identifiant de clic (fbclid de l'URL d'atterrissage, préfixé) ; fbp est l'identifiant navigateur du cookie _fbp. Les deux sont de première partie du point de vue de votre domaine et capturables côté serveur une fois que vous les avez persistés hors de la landing page. Si vous ne les avez pas, le taux de correspondance de Meta chute ; si vous les avez, le taux de correspondance est excellent.

test_event_code vous permet de déclencher des événements de test qui ne comptent pas vers le reporting de production. Câblez toujours ceci d'abord ; vérifiez dans Events Manager Test Events avant de basculer le trafic de production.

L'équivalent API Elido : POST /v1/conversions avec {click_id, event_name: "Purchase", value, currency, order_id, customer: {email, phone}}. Elido normalise et hache selon la spec de Meta, recherche le fbc/fbp du workspace depuis l'événement de clic, et construit le payload CAPI.

Un POST GA4 Measurement Protocol travaillé#

Le format wire de GA4 est similaire en forme mais les noms de champs diffèrent. Endpoint : POST https://www.google-analytics.com/mp/collect?measurement_id=G-XXX&api_secret=xxx.

{
  "client_id": "click-id-as-fallback-if-no-ga4-cookie",
  "user_id": "user-acme-12847",
  "events": [
    {
      "name": "purchase",
      "params": {
        "transaction_id": "order-acme-2026-05-23-001847",
        "value": 89.5,
        "currency": "EUR",
        "items": [
          {
            "item_id": "sku-spring-jeans-32-blue",
            "item_name": "Spring Jeans 32 Blue",
            "quantity": 1,
            "price": 89.5
          }
        ],
        "engagement_time_msec": 1
      }
    }
  ]
}

Notes :

client_id est la valeur _ga du cookie GA4 si présent ; sinon, le click_id fait un fallback utilisable (parce que GA4 créera une session contre lui).

transaction_id est la clé de déduplication - mettez-le à votre ID de commande, même valeur que l'événement purchase gtag du navigateur, GA4 déduplique dans sa fenêtre de session.

engagement_time_msec doit être présent et positif pour que l'événement compte vers l'attribution ; le mettre à 1 satisfait l'exigence.

api_secret est au niveau workspace. Les docs GA4 MP couvrent la configuration des identifiants.

Sémantique de retry#

Les plateformes acceptent les retries ; ce que vous ne pouvez pas faire est réessayer aveuglément. Trois patterns tiennent la route.

Idempotence sur le dedup ID. Si l'event_id / transaction_id de la plateforme est l'ID de commande, et que vous réessayez le même payload, la plateforme déduplique - le second envoi est silencieusement ignoré. Sûr.

Backoff exponentiel sur les 5xx. Meta et GA4 retournent occasionnellement des 5xx. Réessayez avec backoff (1s, 2s, 4s, 8s jusqu'à 60s, puis abandonnez). Les retries doivent préserver le même event_id afin que la plateforme déduplique tout cas de succès partiel.

Ne réessayez pas sur les 4xx. Une réponse 4xx signifie que le payload est malformé ou que les identifiants sont mauvais. Réessayer ne le corrigera pas ; le retry brûle juste du budget de rate-limit. Logguez-le, alertez, corrigez le problème en amont.

Si vous routez via Elido, le retry/backoff est géré - POST /v1/conversions retourne immédiatement et le fan-out vers les plateformes se passe en arrière-plan, avec l'état de retry observable via GET /v1/conversions/{id}. Si vous roulez le vôtre, la couche de queue (RabbitMQ, Kafka, AWS SQS) est là où vit la forme du retry.

Diagramme de décision de retry : un POST de conversion indexé sur l'ID de commande se branche selon la classe de réponse, 2xx marque terminé, 5xx déclenche un backoff exponentiel et un nouveau POST avec le même event_id, et 4xx s'arrête avec un log et une alerte

Mode test et dry-run#

La plus grande erreur que font les équipes est de sauter le dry-run.

Meta a les Test Events. Vous mettez test_event_code sur le payload, les événements apparaissent dans le panneau Test Events en quelques secondes, vous vérifiez la forme et la déduplication. Les événements de production passent par le même endpoint mais sans le test_event_code.

GA4 a DebugView. Vous mettez debug_mode: 1 sur les params de l'événement, les événements apparaissent dans DebugView, vous vérifiez avant de basculer le trafic de production.

TikTok a un mode test similaire dans l'interface Events Manager.

La checklist de vérification est courte. Placez une commande test, observez le webhook order-paid, observez le transfert de conversion se déclencher, observez-le atterrir dans le panneau de test de la plateforme. Confirmez que l'event_id correspond à la valeur du pixel côté navigateur. Confirmez que la valeur, la devise et les content_ids semblent corrects. Puis désactivez le mode test et surveillez les dix premières commandes de production.

Si vous sautez ceci, vous découvrez que l'intégration est cassée trois jours plus tard quand les rapports sont plats. Sauter le dry-run est le mode de défaillance unique le plus courant que je vois.

Modes de défaillance courants#

Click_id manquant sur la commande. Le plus courant. Déjà couvert dans le cornerstone ecommerce ; la correction est de plomber le click_id à travers le panier jusqu'à la commande.

Mismatch de hash. [email protected] haché sans normalisation produit une valeur différente de [email protected]. Les plateformes rejettent la correspondance, la conversion atterrit sans correspondance d'identifiant, et le reporting de Meta l'attribue à « unmatched ». La correction est les règles de normalisation dans le doc des paramètres Meta CAPI ; la réponse plus propre est de déléguer le hachage au raccourcisseur afin que les règles vivent à un seul endroit.

fbc non capturé. Quand l'utilisateur atterrit depuis une pub Meta, l'URL contient fbclid ; la page doit le capturer et le persister (typiquement dans les attributs custom de la commande). Sans fbc, le taux de correspondance de Meta chute matériellement. La correction est l'étape du gestionnaire de tags de la landing page qui écrit fbc dans un cookie de première partie ou dans l'attribut du panier.

Dedup ID incohérent. Le pixel côté navigateur utilise l'ID de commande ; côté serveur utilise un UUID généré au moment du transfert. Les deux événements ingèrent, ni l'un ni l'autre n'est dédupliqué. La correction est de s'assurer que le transfert côté serveur utilise la même valeur d'event_id que celle émise par le pixel côté navigateur - l'ID de commande pour les achats est la réponse standard.

Mismatch de devise. Le navigateur envoie USD (parce que la config gtag par défaut est USD) ; le serveur envoie EUR (parce que la commande est en EUR). GA4 et Meta traitent tous deux la devise comme partie de la signature de l'événement dans certains contextes de correspondance, et les conversions atterrissent mais ne s'agrègent pas proprement. La correction est de sourcer la devise depuis la commande, pas depuis la config au niveau page.

Où ceci vit dans le plan de données#

Le transfert de conversion est une pièce du pipeline d'attribution plus large. Le cornerstone pour le pipeline environnant est Comment suivre les campagnes UTM end-to-end sans CDP - ce billet couvre le template UTM workspace, les surcharges au niveau campagne, l'import en bulk et l'étape de vérification dry-run en détail. Ce billet est le drill-down plus profond sur le fan-out côté serveur qui ferme la boucle.

Pour le guide opérationnel, le doc de transfert de conversion est le pas-à-pas. Pour le détail architectural derrière la façon dont Elido fait du fan-out sans dépasser les rate limits des plateformes, le billet sur l'architecture d'ingestion de clics couvre le pipeline fire-and-forget.

Lire le cluster#

Billets frères du cluster features : Smart links expliqués (le cornerstone), Webhooks pour événements de lien (la forme d'événement plus large), et Transférer les conversions vers Meta CAPI (le drill-down spécifique Meta plus profond). Pour la version orientée persona, solutions/marketers est la page ; la page produit suivi des conversions est la surface produit.

Pour aller plus loin sur le blog#

Essayer Elido

Collez une URL, obtenez un lien court

Sans inscription. Lien actif 30 jours. Inscrivez-vous pour le garder pour toujours.

Gratuit, sans inscription · 2 par jour

Essayer Elido

Raccourcisseur d'URL hébergé en UE : domaines personnalisés, analyses approfondies et API ouverte. Forfait gratuit - sans carte bancaire.

Tags
server side conversion tracking
meta capi
ga4 server side
conversion api
tiktok events api
deduplication
click_id

Lire la suite