Pipeline Automatizado de Conversiones Offline a Google Ads y HubSpot
Integración paso a paso con Google Ads API (UploadClickConversions), hashing SHA-256 de identificadores first-party y sincronización webhook bidireccional con HubSpot.
Cuando una oportunidad B2B se cierra tras meses de negociación, el valor final del contrato reside en el CRM o ERP de la empresa. Si esa señal de conversión no vuelve a Google Ads, el algoritmo de puja automática seguirá optimizando campañas hacia usuarios que rellenan formularios sin intención de compra. Este pipeline extrae transacciones ganadas desde el Data Warehouse y las inyecta de forma segura en la API de Google Ads y HubSpot.
1. Captura Persistente de Identificadores (GCLID / GBRAID / WBRAID)
Para atribuir una conversión offline que ocurre 90 días después del primer clic, el parámetro `gclid` (o el identificador de modelado para iOS `gbraid`/`wbraid`) debe capturarse en la primera visita del usuario y persistirse en una cookie first-party `HttpOnly` y en campos ocultos del formulario web.
Buenas Prácticas de Captura
Almacena siempre el gclid junto a la marca de tiempo de captura. Google Ads acepta conversiones offline hasta 90 días posteriores a la fecha del clic original.
2. Estructuración del Payload para Google Ads API (v17)
El servicio `ConversionUploadService.uploadClickConversions` recibe la lista de conversiones. Se incluye el valor monetario (`conversion_value`), la moneda (`currency_code`), la fecha formateada en zona horaria y los datos de usuario normalizados con SHA-256.
// Payload estructurado para la API de Google Adsinterface OfflineConversionPayload {conversionAction: string; // resource name: customers/{customer_id}/conversionActions/{conversion_action_id}gclid?: string;conversionDateTime: string; // Formato: 'yyyy-mm-dd hh:mm:ss+|-hh:mm'conversionValue: number;currencyCode: string;userIdentifiers?: Array<{hashedEmail?: string;hashedPhoneNumber?: string;}>;}export async function uploadOfflineConversion(customerId: string,developerToken: string,authToken: string,conversion: OfflineConversionPayload) {const endpoint = `https://googleads.googleapis.com/v17/customers/${customerId}:uploadClickConversions`;const response = await fetch(endpoint, {method: 'POST',headers: {'Authorization': `Bearer ${authToken}`,'developer-token': developerToken,'Content-Type': 'application/json'},body: JSON.stringify({conversions: [conversion],partialFailure: true})});return await response.json();}
3. Actualización de Propiedades en HubSpot CRM
En paralelo, cuando el pipeline detecta que la conversión se ha procesado con éxito, emite una llamada a la API de HubSpot para marcar la propiedad `sync_status = "SYNCHRONIZED_TO_ADS"` y registrar la fecha exacta, evitando duplicados en ejecuciones posteriores.
{"properties": {"marketing_offline_conversion_synced": "true","google_ads_sync_timestamp": "2026-09-05T14:30:00Z","calculated_net_margin_value": "18450.00","last_sync_log_id": "job_revops_89412"}}
4. Diagnóstico de Errores Comunes en Subidas Offline
La siguiente tabla recopila los códigos de error más frecuentes devueltos por la API de Google Ads y sus soluciones inmediatas en producción.
| Código de Error API | Causa Raíz | Solución en el Pipeline |
|---|---|---|
| CLICK_NOT_FOUND | El GCLID no existe o tiene más de 90 días | Filtrar eventos donde NOW() - click_date > 89 días |
| CONVERSION_PRECEDES_CLICK | conversionDateTime es anterior al clic | Verificar zonas horarias (UTC vs. hora local de la cuenta) |
| EXPIRED_GCLID | El clic expiró la ventana de atribución | Fallback a Enhanced Conversions con hashed_email |
| UNAUTHORIZED_CUSTOMER | Token OAuth sin permisos sobre el MCC | Renovar refresh token con permisos admin sobre cuenta hija |
Controles Técnicos
Muestra telemetría y especificaciones de verificación en producción.