Automatiser l'envoi de conversions via l'API Google Ads
L'import manuel de conversions ne passe pas à l'échelle. Pour automatiser, vous devez utiliser l'API Google Ads. Voici un guide technique pour développer votre propre intégration.
Prérequis
Avant de commencer, vous aurez besoin de :
- Un compte Google Ads avec des conversions configurées
- Un projet Google Cloud Platform avec l'API Google Ads activée
- Un token développeur Google Ads (niveau Basic ou Standard)
- Des credentials OAuth 2.0 pour l'authentification
- Un refresh token pour l'authentification persistante
Étape 1 : Configurer l'accès API
Créer un projet GCP
- Allez sur console.cloud.google.com
- Créez un nouveau projet ou sélectionnez-en un existant
- Activez l'API Google Ads dans "APIs & Services"
Créer des credentials OAuth
- Dans GCP, allez dans APIs & Services > Credentials
- Créez un OAuth 2.0 Client ID de type "Web application"
- Notez le Client ID et Client Secret
Obtenir un token développeur
- Dans Google Ads, allez dans Outils > Configuration > Centre API
- Demandez un token développeur (niveau Basic suffit pour commencer)
- Notez le token une fois approuvé
Générer un refresh token
Utilisez l'outil OAuth Playground de Google ou le script fourni par la bibliothèque cliente :
// Avec la bibliothèque Python google-ads
pip install google-ads
// Exécuter le script d'authentification
python -m google_ads.client oauth2
Étape 2 : Structure de l'appel API
L'endpoint pour uploader des conversions offline est UploadClickConversions du service ConversionUploadService.
Format de la requête
{
"customerId": "1234567890",
"conversions": [
{
"gclid": "EAIaIQobChMI...",
"conversionAction": "customers/1234567890/conversionActions/987654321",
"conversionDateTime": "2025-11-20 14:30:00+01:00",
"conversionValue": 1500.00,
"currencyCode": "EUR"
}
],
"partialFailure": true
}
Champs obligatoires
- customerId : ID du compte Google Ads (sans tirets)
- gclid : L'identifiant du clic Google Ads (comment le capturer)
- conversionAction : Resource name de l'action de conversion
- conversionDateTime : Date/heure de la conversion (avec timezone)
Champs optionnels mais recommandés
- conversionValue : Valeur de la conversion
- currencyCode : Devise (EUR, USD, etc.)
- orderId : ID unique pour éviter les doublons
Étape 3 : Implémentation en Python
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
from datetime import datetime
import pytz
# Configuration
CUSTOMER_ID = "1234567890"
CONVERSION_ACTION_ID = "987654321"
# Initialiser le client
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
def upload_offline_conversion(gclid, conversion_time, value, currency="EUR"):
"""
Upload une conversion offline vers Google Ads.
Args:
gclid: L'identifiant du clic Google Ads
conversion_time: datetime de la conversion
value: Valeur de la conversion
currency: Devise (default EUR)
"""
conversion_upload_service = client.get_service("ConversionUploadService")
conversion_action_service = client.get_service("ConversionActionService")
# Construire le resource name de l'action de conversion
conversion_action_resource = conversion_action_service.conversion_action_path(
CUSTOMER_ID, CONVERSION_ACTION_ID
)
# Créer l'objet conversion
click_conversion = client.get_type("ClickConversion")
click_conversion.gclid = gclid
click_conversion.conversion_action = conversion_action_resource
click_conversion.conversion_date_time = conversion_time.strftime("%Y-%m-%d %H:%M:%S%z")
click_conversion.conversion_value = value
click_conversion.currency_code = currency
# Upload
request = client.get_type("UploadClickConversionsRequest")
request.customer_id = CUSTOMER_ID
request.conversions.append(click_conversion)
request.partial_failure = True
try:
response = conversion_upload_service.upload_click_conversions(request=request)
# Vérifier les erreurs partielles
if response.partial_failure_error:
print(f"Erreur partielle: {response.partial_failure_error.message}")
# Log les résultats
for result in response.results:
if result.gclid:
print(f"Conversion uploadée pour GCLID: {result.gclid}")
else:
print("Conversion uploadée (sans GCLID retourné)")
return True
except GoogleAdsException as ex:
print(f"Erreur Google Ads: {ex.failure.errors[0].message}")
return False
# Exemple d'utilisation
if __name__ == "__main__":
paris_tz = pytz.timezone("Europe/Paris")
conversion_time = paris_tz.localize(datetime(2025, 11, 20, 14, 30, 0))
upload_offline_conversion(
gclid="EAIaIQobChMIwPLn5YXx9QIVhOvtCh2xGwKXEAAYASAAEgLwN_D_BwE",
conversion_time=conversion_time,
value=1500.00
)
Fichier de configuration (google-ads.yaml)
developer_token: VOTRE_DEVELOPER_TOKEN
client_id: VOTRE_CLIENT_ID.apps.googleusercontent.com
client_secret: VOTRE_CLIENT_SECRET
refresh_token: VOTRE_REFRESH_TOKEN
login_customer_id: VOTRE_MCC_ID # Si vous utilisez un MCC
Étape 4 : Implémentation en PHP
<?php
require 'vendor/autoload.php';
use Google\Ads\GoogleAds\Lib\V15\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\V15\Services\ClickConversion;
use Google\Ads\GoogleAds\V15\Services\UploadClickConversionsRequest;
$customerId = '1234567890';
$conversionActionId = '987654321';
// Initialiser le client
$googleAdsClient = (new GoogleAdsClientBuilder())
->fromFile('/path/to/google_ads_php.ini')
->build();
function uploadOfflineConversion(
$client,
$customerId,
$conversionActionId,
$gclid,
$conversionTime,
$value,
$currency = 'EUR'
) {
$conversionUploadService = $client->getConversionUploadServiceClient();
// Resource name de l'action de conversion
$conversionActionResource = sprintf(
'customers/%s/conversionActions/%s',
$customerId,
$conversionActionId
);
// Créer la conversion
$clickConversion = new ClickConversion();
$clickConversion->setGclid($gclid);
$clickConversion->setConversionAction($conversionActionResource);
$clickConversion->setConversionDateTime($conversionTime->format('Y-m-d H:i:sP'));
$clickConversion->setConversionValue($value);
$clickConversion->setCurrencyCode($currency);
// Requête d'upload
$request = new UploadClickConversionsRequest();
$request->setCustomerId($customerId);
$request->setConversions([$clickConversion]);
$request->setPartialFailure(true);
try {
$response = $conversionUploadService->uploadClickConversions($request);
// Vérifier les erreurs partielles
if ($response->hasPartialFailureError()) {
echo "Erreur partielle: " . $response->getPartialFailureError()->getMessage();
}
foreach ($response->getResults() as $result) {
echo "Conversion uploadée pour GCLID: " . $result->getGclid() . "\n";
}
return true;
} catch (Exception $e) {
echo "Erreur: " . $e->getMessage();
return false;
}
}
// Exemple d'utilisation
$conversionTime = new DateTime('2025-11-20 14:30:00', new DateTimeZone('Europe/Paris'));
uploadOfflineConversion(
$googleAdsClient,
$customerId,
$conversionActionId,
'EAIaIQobChMIwPLn5YXx9QIVhOvtCh2xGwKXEAAYASAAEgLwN_D_BwE',
$conversionTime,
1500.00
);
Étape 5 : Intégration avec votre CRM
L'idéal est de déclencher l'upload automatiquement quand un lead change de statut dans votre CRM.
Architecture recommandée
- Webhook CRM : Le CRM envoie un webhook quand un deal passe en "Gagné"
- Service d'upload : Reçoit le webhook, récupère le GCLID, envoie à Google Ads
- Queue : Utiliser une queue (Redis, RabbitMQ) pour gérer les erreurs et retries
Exemple avec webhook
# Endpoint Flask recevant le webhook
from flask import Flask, request
import json
app = Flask(__name__)
@app.route('/webhook/deal-won', methods=['POST'])
def handle_deal_won():
data = request.json
# Extraire les données nécessaires
gclid = data.get('gclid')
deal_value = data.get('deal_value')
closed_at = data.get('closed_at')
if not gclid:
return {'status': 'skipped', 'reason': 'no_gclid'}, 200
# Convertir la date
conversion_time = datetime.fromisoformat(closed_at)
# Upload vers Google Ads
success = upload_offline_conversion(
gclid=gclid,
conversion_time=conversion_time,
value=deal_value
)
if success:
return {'status': 'success'}, 200
else:
return {'status': 'error'}, 500
Gestion des erreurs
Erreurs courantes
| Erreur | Cause | Solution |
|---|---|---|
| INVALID_GCLID | GCLID mal formaté ou expiré | Vérifier le format, respecter les 90 jours |
| TOO_RECENT_CONVERSION | Conversion uploadée trop tôt | Attendre quelques heures après le clic |
| DUPLICATE_CONVERSION | Même conversion déjà importée | Utiliser orderId pour dédupliquer |
| EXPIRED_GCLID | GCLID de plus de 90 jours | Importer plus rapidement |
Stratégie de retry
import time
from functools import wraps
def retry_on_failure(max_retries=3, delay=60):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt < max_retries - 1:
time.sleep(delay * (attempt + 1))
else:
raise e
return wrapper
return decorator
@retry_on_failure(max_retries=3, delay=60)
def upload_with_retry(gclid, conversion_time, value):
return upload_offline_conversion(gclid, conversion_time, value)
Monitoring et logging
Pour un système de production, implémentez :
- Logging détaillé : Chaque tentative d'upload avec résultat
- Métriques : Taux de succès, temps de réponse, erreurs par type
- Alertes : Notification si taux d'erreur anormal
- Dashboard : Vue en temps réel des conversions uploadées
LeadZen : l'API en mode SaaS
Pourquoi développer quand vous pouvez utiliser LeadZen ? Notre plateforme gère l'authentification, les retries, le monitoring et l'envoi vers Google Ads. Vous vous concentrez sur votre business.
Essayer gratuitement pendant 30 joursBonnes pratiques
1. Utilisez orderId pour la déduplication
Ajoutez un identifiant unique à chaque conversion pour éviter les doublons en cas de retry :
click_conversion.order_id = f"deal_{deal_id}"
2. Respectez les quotas
L'API Google Ads a des limites de requêtes. Pour des volumes importants :
- Batchez les conversions (jusqu'à 2000 par requête)
- Espacez les requêtes
- Demandez une augmentation de quota si nécessaire
3. Gérez les timezones
La date de conversion doit inclure le timezone. Utilisez toujours un format avec offset :
"2025-11-20 14:30:00+01:00" // Correct
"2025-11-20 14:30:00" // Incorrect (timezone manquant)
4. Validez avant d'envoyer
Avant l'upload, vérifiez :
- GCLID non vide et format valide (~100 caractères)
- Date de conversion dans les 90 jours
- Valeur numérique positive
Conclusion
L'API Google Ads permet d'automatiser complètement l'import de vos conversions offline. C'est un investissement technique initial, mais le gain en fiabilité et en temps est significatif.
Les 3 points clés :
- Configurez correctement l'authentification : C'est la partie la plus complexe
- Gérez les erreurs et retries : L'API peut échouer temporairement
- Utilisez orderId pour éviter les doublons
Pas envie de développer ? Essayez LeadZen pour automatiser l'envoi de vos conversions sans écrire une ligne de code.