He cableado el tracking UTM de extremo a extremo en tres empresas. Cada vez, las mismas cinco cosas se rompieron en el mismo orden, y cada vez la solución fue la misma: tirar de las plantillas hacia arriba al nivel de campaña, empujar el reenvío de conversiones hacia abajo al servidor y poner un dry run entre ellos. Eso es la mayor parte de lo que es esta publicación. El resto es la checklist de QA que detecta las cosas que no pensaste en romper.
No necesitas una Customer Data Platform para esto. Eventualmente necesitarás una si tu problema de atribución se convierte en "coser cuatro toques anónimos a través de tres dispositivos en un viaje de cliente", pero para el caso que veo más a menudo - "etiquetar cada enlace saliente de forma consistente, capturar el clic, reenviar la conversión a Meta y GA4 server-side, y sobrevivir a Safari" - un acortador de URL con plantillas más una API de conversiones hace el trabajo. A continuación está la versión que funciona, con los modos de fallo que he visto destacados.
Qué sale mal con el tracking UTM#
Los marketers con los que trabajo no son malos con UTMs. El problema es que las herramientas por defecto hacen que sea fácil escribir un UTM una vez, difícil aplicarlo en toda una organización e imposible arreglarlo después del lanzamiento. Cuatro modos de fallo aparecen una y otra vez.
Drift. Una persona escribe utm_source=newsletter, otra escribe utm_source=Newsletter, una tercera escribe utm_source=email. Seis meses después tu canal "newsletter" está dividido en nueve variantes de cadena en GA4. Limpiarlo después es un ejercicio de regex-y-rezar. El script original urchinTracker() que introdujo esta convención - el producto pre-Analytics de Google Urchin web analytics, open-sourced brevemente en 2003 antes de ser absorbido - no tenía capa de plantilla tampoco. La convención siempre fue "escríbelo consistentemente"; el tooling nunca lo aplicó.
Etiquetado manual a escala. Una campaña de folletos con 80 enlaces cortos en cuatro escaparates regionales son 320 URLs que tienes que escribir, pegar en una hoja de cálculo, copiar en tu acortador y rezar. La mitad de ellos obtienen el utm_content equivocado. Nadie lo nota hasta que la campaña lleva dos semanas.
Brechas de conversión server-side. El pixel se dispara en la página de gracias, GA4 lo recoge, Meta lo recoge, y te vas a casa. Luego Safari lanza otra versión de ITP, las instalaciones de bloqueadores de anuncios suben, y tus conversiones reportadas caen un tercio. Las notas de la versión ITP 2.3 de Apple recorren exactamente el mecanismo: la decoración de enlaces está throttled, document.referrer está eliminado, y cualquier flujo de analítica que depende del navegador ejecutando JS de terceros se degrada silenciosamente. Las conversiones siguen ocurriendo en tu servidor. Simplemente no están llegando a las superficies publicitarias.
Sin dry-run. La primera conversión que fluye a través del nuevo pipeline es el primer comprador real. Si algo está mal configurado, te enteras tres días después cuando el algoritmo de optimización ya ha sacado presupuesto de una campaña que realmente funcionaba.
Esta publicación aborda los tres primeros con plantillas + importación masiva + reenvío server-side, y el cuarto con un paso de verificación que es fácil saltarse y caro saltarse.
Plantillas UTM de workspace y campaña#
Las plantillas empujan el problema de consistencia hacia arriba en el stack. Defines tu convención de etiquetado una vez a nivel de workspace, capas overrides por campaña donde están justificados, y dejas que cada enlace herede. No queda lugar para que un typo viva.
Define los predeterminados del workspace primero. Los valores literales fijan las variables que nunca cambian para tu organización (utm_medium = email para campañas de boletín); los placeholders se rellenan del payload del enlace en el momento de creación:
curl -X PUT \
https://api.elido.app/v1/workspaces/1/utm-template \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-d '{
"utm_source": "{{ channel }}",
"utm_medium": "{{ medium }}",
"utm_campaign": "{{ campaign }}",
"utm_content": "{{ creative }}",
"utm_term": "{{ audience.segment }}"
}'
Algunos detalles que importan aquí:
- Los placeholders se rellenan en la creación del enlace, no en el momento del clic. Lo que aterriza en tu herramienta de analítica es lo que se pretendía en el momento en que se acuñó el enlace - no lo que el destino del enlace computó en el clic. Esto hace que la reconstrucción del registro de auditoría sea mucho más fácil cuando algo parece mal seis meses después.
- Los placeholders desconocidos fallan rápido. Si tu importación masiva carece de una columna
creativey la plantilla del workspace referencia{{ creative }}, la API devuelve un 422 con el nombre de la variable no resuelta. Sin aplicación parcial silenciosa. - La referencia completa de la plantilla, incluyendo placeholders
link.tag.<name>que leen del array de tags del enlace (útil para agencias multi-tenant que necesitan incrustar un identificador de cliente en cada URL), está en la guía de docs.
Luego capa una plantilla de campaña. Las campañas heredan del workspace y reemplazan el subconjunto que es específico de la campaña:
curl -X POST \
https://api.elido.app/v1/campaigns \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-d '{
"name": "Spring 2026 - DACH",
"utm_template": {
"utm_campaign": "spring_2026_dach",
"utm_term": "{{ audience.locale }}"
}
}'
Cualquier cosa no establecida en la campaña cae a los predeterminados del workspace. El layering de dos niveles cubre la mayoría de las estructuras organizativas reales: convenciones compartidas a nivel de workspace, overrides específicos del equipo o de la temporada a nivel de campaña. Si te encuentras queriendo un tercer nivel de herencia, eso es una señal - generalmente significa que dos campañas deberían ser una campaña con valores de placeholder más inteligentes.
Lo que los overrides por enlace ceden: un override se dispara independientemente de la plantilla. Lo que mantienen: el override se registra en el log de auditoría con actor + timestamp + el diff resuelto-vs-final. Dentro de seis meses, cuando alguien pregunte por qué un enlace en una campaña de 200 enlaces tiene utm_term=manual_override, puedes responder.
Importación masiva desde Sheets - el flujo que la mayoría de los marketers realmente usan#
Los marketers no se sientan en curl todo el día. El brief de campaña aterriza como una hoja de cálculo con URLs de destino y metadatos de campaña, la fecha límite de lanzamiento es el viernes, y la pregunta es cómo esa hoja de cálculo se convierte en 200 enlaces cortos sin que nadie escriba la misma cadena UTM 200 veces.
Los nombres de columna CSV coinciden con los nombres de placeholder de tu plantilla (insensible a mayúsculas). Las columnas que Elido no reconoce se descartan con una advertencia en lugar de copiarse silenciosamente - esto es deliberado. La copia silenciosa es cómo terminas con utm_brand_color apareciendo en GA4 porque alguien añadió una columna para una nota interna.
destination_url,channel,medium,creative
https://shop.example.com/de,newsletter,email,hero_a
https://shop.example.com/fr,newsletter,email,hero_a
https://shop.example.com/de,paid_social,meta,carousel_v2
https://shop.example.com/fr,paid_social,meta,carousel_v2
Hazle POST como multipart:
curl -X POST \
https://api.elido.app/v1/links/bulk \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-F "csv=@launch_q2.csv" \
-F "campaign_id=cmp_8a2f"
Dos cosas que este flujo de validación te compra que una UI de un-enlace-a-la-vez no:
- Commit todo-o-nada. Una sola fila mala aborta toda la subida y devuelve los números de línea ofensivos más la razón -
row 47: unresolved variable {{ creative }}es un error mucho mejor que descubrir a las 4pm de un viernes que 47 de tus 200 enlaces se resolvieron a una cadena placeholder. - Vista previa pre-lanzamiento. La fila de vista previa de importación masiva del dashboard muestra la URL resuelta, incluyendo la cadena de consulta
utm_*renderizada, antes del commit. Mira el segundo enlace para asegurarte de que tu plantilla hizo lo que esperabas, luego mira el último enlace para asegurarte de que las filas hacia abajo en el archivo no derivaron. Dos vistazos, un minuto.
Si tu hoja de cálculo no tiene una forma estable - los órdenes de columna se mezclan, las cabeceras se renombran - el endpoint de importación masiva va a ser desagradable. La solución no está en nuestro tooling; la solución es comprometerse con un esquema CSV para tus briefs de campaña y tratar el drift de esquema como un bug de proceso. Discutimos el patrón más amplio en la página de soluciones de marketers.
Reenvío de conversiones server-side a Meta CAPI y GA4#
La atribución solo-pixel pierde 20-40% de conversiones a ITP de Safari, bloqueadores de anuncios y banners de consentimiento. El número varía por industria - ecommerce DTC ve el extremo alto del rango, B2B SaaS el extremo bajo - pero cada medición que he visto post-iOS 14 sitúa la fiabilidad del pixel muy por debajo de la marca del 95% que las plataformas publicitarias asumen. El algoritmo de optimización obtiene entradas más ruidosas y tu CPA parece peor de lo que es.
La documentación de Conversions API de Meta es explícita sobre esto: los eventos del servidor son lo que quieres, el pixel del lado del navegador es el suplemento. Measurement Protocol de GA4 hace el mismo caso. Ambos protocolos aceptan la misma forma: un evento server-side con los detalles de la conversión, un event_id para deduplicación, e idealmente identificadores de usuario hasheados para que las plataformas puedan coser la conversión a un visitante conocido.
El cableado que cierra la brecha es mecánico. Tres pasos.
Paso uno - capturar el click_id. Cada respuesta de redirección de Elido lleva una cabecera X-Elido-Click-Id. Los SDKs de TS / Python / Go la exponen en el objeto de respuesta de redirección; HTTP en bruto también funciona:
curl -sI https://elido.me/launch | grep -i click-id
# X-Elido-Click-Id: clk_01HYZ7T8WV6KQX3M
Guárdalo en una cookie de primera parte en la página de destino (elido_click_id, TTL de 90 días - lo suficientemente largo para cubrir una evaluación SaaS típica, lo suficientemente corto para satisfacer la guía ePrivacy). Léelo de vuelta en el checkout.
Paso dos - cablear los destinos. Haz PUT de las credenciales para las superficies a las que quieres reenviar. Cualquier subconjunto funciona; las superficies faltantes se saltan silenciosamente:
curl -X PUT \
https://api.elido.app/v1/workspaces/1/conversion-forwarding \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-d '{
"meta_capi": {
"pixel_id": "1234567890",
"access_token": "EAA…",
"test_event_code": null
},
"ga4_mp": {
"measurement_id": "G-ABC123",
"api_secret": "abc_def_ghi"
},
"mixpanel": {
"project_token": "pm_…",
"service_account": "[email protected]"
}
}'
Paso tres - POST la conversión. Cuando el pedido se dispara, envía el evento con el click_id y los detalles del pedido. event_id es tu clave de idempotencia:
curl -X POST \
https://api.elido.app/v1/conversions \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-d '{
"click_id": "clk_01HYZ7T8WV6KQX3M",
"event_name": "purchase",
"event_id": "ord_98231",
"value": 89.00,
"currency": "EUR",
"user": {
"email": "[email protected]",
"phone": "+4915123456789",
"external_id": "cust_5128"
}
}'
Los campos de identidad del usuario se hashean con SHA-256 antes de reenviarse a Meta y GA4 - esto es lo que ambas plataformas requieren. El contexto UTM se extrae de la fila de clic que coincide con click_id, por lo que el evento reenviado lleva la atribución de campaña original incluso si el usuario vagó por el sitio durante una hora antes de hacer checkout. La mecánica completa, incluyendo el manejo de reembolsos y el toggle del modelo de atribución multi-touch, está en la guía de reenvío de conversiones.
Esto es la mayor parte de la brecha cerrada. Hay un agujero residual - visitantes que bloquean la cookie del click_id, o llegan a través de una ruta no-Elido - pero para las campañas a las que realmente impulsas tráfico, has pasado de "60-80% de fiabilidad de pixel" a "95%+ de fiabilidad del servidor".
Tres casos extremos en los que el log de auditoría te salvará#
Las plantillas y el reenvío manejan el camino feliz. Los casos a continuación aparecen en la semana tres de cualquier campaña no trivial, y la respuesta correcta a todos ellos vive en el log de auditoría + el panel de conversiones - no en intentar diseñar una plantilla más elaborada.
Reembolsos. Una conversión de compra se disparó, el cliente devolvió el artículo una semana después, y tus ingresos reportados ahora son 8% demasiado altos. La solución es hacer POST del mismo event_id con event_name: "refund". Meta y GA4 lo tratan como una conversión negativa contra el original; Mixpanel lo registra como un evento separado que restas en tu embudo. La razón por la que event_id tiene esta forma: la idempotencia a nivel de event id significa que tampoco puedes contar dos veces el reembolso. El patrón completo está documentado en la sección de casos extremos de la guía de reenvío de conversiones - reembolsos, reembolsos parciales y crédito de tienda cada uno tiene una forma ligeramente diferente.
Fallos de click-id. Una conversión se dispara con un click_id que no coincide con ningún clic conocido - typo, expirado más allá de la retención, workspace equivocado. La conversión todavía se registra contra el workspace pero se reenvía con contexto UTM vacío. Esto es intencional: la atribución catch-all es más útil que dejar caer la conversión al suelo, y la bandera click_id_unknown en el log de auditoría te permite filtrar la porción no atribuida al reportar. Si la porción es mayor que el 5% de las conversiones, algo está mal con cómo persistes el click_id en la página de destino - generalmente el atributo SameSite de la cookie o el alcance de la ruta.
Conversiones de llegada tardía. Una venta B2B SaaS se cierra 47 días después del clic original. La retención predeterminada de clics de Elido es de 30 días, por lo que para cuando la conversión se dispara, el clic ha caducado y estás en el caso de fallo de click-id anterior. Dos soluciones, dependiendo de tu ciclo de ventas: aumenta la retención a 90 días en el workspace (plan Pro y superior), o captura el click_id en un identificador de primera parte de larga duración (la columna original_click_id del registro de cliente) para que puedas coserlo de vuelta en el momento de la conversión incluso si la cookie se ha ido. Hemos visto ambos patrones en producción.
El log de auditoría muestra el diff UTM resuelto-vs-final por enlace, el código de respuesta de reenvío por destino por conversión, y el estado de unión click_id-a-conversión. Cuando el algoritmo de optimización saca presupuesto de una campaña que parece tener bajo rendimiento, el log de auditoría es lo que te permite decir "no, la campaña está bien; perdimos tres días de reenvío por un api_secret de GA4 rotado". Míralo.
El QA pre-lanzamiento - dry-run de todo el pipeline#
No dejes que la primera conversión que fluya a través de esto sea un comprador real. El coste de un dry run de 30 minutos lo asumes enteramente tú; el coste de un pipeline mal configurado lo asume el algoritmo de optimización sacando presupuesto de tu campaña con mejor rendimiento durante dos días antes de que lo notes. La asimetría es mala.
Tres pasos, en orden.
Dry run de importación masiva. El endpoint de importación masiva acepta dry_run=true como parámetro de consulta. Ejecuta la validación, resuelve las plantillas y devuelve los enlaces que se habrían creado sin commit. Abre la respuesta en cualquier visor JSON; la URL resuelta de cada fila es visible. Comprueba 3-5 filas: el segundo enlace, el último enlace, y cualquier fila que haya anulado los predeterminados del workspace. Verifica que la cadena de consulta utm_* es exactamente lo que tu brief de campaña dice que debería ser.
Modo de prueba de reenvío de conversiones. Meta CAPI acepta un parámetro test_event_code, que enruta el evento a la pestaña Test Events en Events Manager en lugar de producción. Configúralo en la configuración de reenvío del workspace, envía 10-20 conversiones de muestra y confirma que aterrizan. Misma idea para GA4: establece debug_mode: true en los eventos y verifica en DebugView. Ambos son en tiempo real. El punto no es comprobar que la API funciona; el punto es atrapar un pixel_id mal configurado o un api_secret que fue rotado y nunca actualizado.
Smoke de extremo a extremo. Haz clic en uno de tus enlaces cortos reales desde una sesión de navegador limpia. Observa el clic en el panel de clics recientes del dashboard de Elido. Pretende que compraste algo - haz POST de una conversión purchase con ese click_id desde tu terminal. Confirma que la conversión aparece en Meta Test Events y GA4 DebugView con el contexto UTM correcto adjunto. Todo el bucle es menos de 10 minutos una vez que lo has hecho una vez.
Después de que los tres pasen, elimina el test_event_code, configura debug_mode: false y lanza. El primer comprador real tendrá un pipeline limpio esperándolo.
Cuándo realmente querrías un CDP#
Plantillas más importación masiva más reenvío server-side te lleva la mayor parte del camino. Hay una clase de problemas donde no lo hace, y alcanzar un CDP es la decisión correcta.
Costura de identidad cross-dispositivo. Un visitante hace clic en un enlace en móvil, no convierte, vuelve en escritorio, se registra. Quieres que ambos toques se atribuyan a la misma persona. El tracking UTM + click_id es a nivel de toque; la capa de identidad de usuario que hace que los dos toques sean un viaje es para lo que está construido un CDP (Segment, mParticle, RudderStack). Elido almacena hasta 30 días de clics por visitante y admite atribución last-touch / first-touch / position-based dentro de esa ventana, pero la unión cross-dispositivo necesita un grafo de identidad que deliberadamente no operamos.
Personalización sub-100ms. Si estás renderizando la página de destino basada en los toques previos del visitante en tiempo real - extrayendo la cohorte de un feature store y variando el titular del hero - necesitas la resolución de identidad cerca del renderizado. Eso es territorio de CDP o, más a menudo, una plataforma de experimentación como PostHog o LaunchDarkly por encima.
Atribución multi-touch a escala. Last-touch está bien para la mayoría de las campañas. Si tu ciclo de ventas tiene seis toques durante cuatro meses y realmente necesitas acreditar a cada uno, estás en el territorio donde la atribución Markov-chain o Shapley-value empieza a importar. Elido hace last-touch / first-touch / position-based; cualquier cosa más sofisticada quiere una herramienta con un grafo de identidad apropiado y una capa de modelo.
Para todo lo demás - y "todo lo demás" es la mayoría de los equipos de marketing con los que he trabajado - el patrón de plantillas + importación masiva + reenvío server-side es suficiente. Configura la plantilla del workspace una vez, la plantilla de campaña por lanzamiento, la configuración de reenvío una vez por integración de plataforma, y ejecuta el dry run antes de cada lanzamiento. Si haces los cuatro, tendrás un pipeline UTM más estrecho que el 80% de los equipos de marketing que he auditado.
Constrúyelo una vez, haz dry-run antes de cada lanzamiento y pasa a la siguiente campaña.
Relacionados en el blog#
Prueba Elido
Pega una URL, obtén un enlace corto
Sin registro. El enlace vive 30 días. Crea una cuenta para conservarlo.
Gratis, sin registro · 2 por día