Saltar al contenido

GuíasPlataformas publicitarias11 min de lectura

Deduplicación en Meta CAPI: cómo funciona realmente event_id

Cómo empareja Meta los eventos del píxel y de CAPI con event_id y event_name, por qué un desajuste duplica compras y cómo verificar la deduplicación.

Publicado
Revisado
Dos identificadores coincidentes, una sola compra contabilizada.

Daniil MaximkinIngeniero de producto y soluciones

Respuesta corta

Meta deduplica un evento del píxel del navegador y su gemelo en la Conversions API del servidor cuando ambos llevan el mismo event_id y el mismo event_name, recibidos en un plazo de 48 horas. Si los identificadores difieren, se regeneran por carga de página o una de las partes los omite, Meta conserva ambos: infla el recuento de compras y el ROAS. Genera un identificador por evento y pásalo a la opción eventID de fbq y al campo event_id del servidor.

— Daniil

Conclusiones clave

  • La deduplicación exige que coincidan event_id Y event_name en ambas fuentes. Si falla cualquiera de los dos, los dos eventos cuentan.
  • La ventana de deduplicación es de 48 horas desde el primer evento con un event_id dado que recibe Meta.
  • En Shopify la causa habitual son dos sistemas que disparan la misma compra: el canal nativo de Facebook e Instagram más una CAPI vía GTM o app, o una app de CAPI que convive con el píxel del tema.
  • Verifícalo en Test Events de Events Manager, donde las parejas emparejadas llevan la etiqueta «Deduplicated». El panel agregado oculta el problema.
  • Usa un identificador estable ligado al pedido, no un UUID nuevo por carga de página, para que el navegador y el servidor coincidan entre recargas y reintentos.
En esta guía

Antes de cambiar nada: comprueba una compra

Si parece que Meta cuenta una compra dos veces, empieza por una compra conocida y los eventos ya disponibles en Events Manager o en los registros de la integración. No desactives una integración que funciona ni hagas otro pedido de pago solo para esta comprobación.

  1. Enumera las fuentes. Anota qué canal nativo, apps y contenedores de GTM envían Purchase y a qué conjunto de datos.
  2. Compara una pareja. Para esa misma compra, anota el eventID del navegador, el event_id del servidor y los nombres de evento. Indica si coinciden, difieren o no están disponibles; no supongas los valores que falten.
  3. Separa la observación del diagnóstico. Dos registros recibidos o una diferencia entre los totales de Meta y Shopify no bastan para demostrar que una compra se ha contado dos veces. Conserva los detalles del evento y el periodo para revisarlos.

Si los valores difieren o una app los oculta, prepara una descripción para revisar Purchase en Meta. Así trasladas estas observaciones a la solicitud sin enviar datos de clientes ni cambiar antes la configuración.

¿Cómo empareja Meta un evento del navegador con su gemelo en el servidor?

La Conversions API de Meta está diseñada para funcionar junto al Pixel del navegador, no en lugar de él. Ambos deben describir la misma acción real desde dos puntos de vista: el Pixel se dispara desde el navegador del comprador, la Conversions API envía el mismo evento desde tu servidor.

Enviar los dos es la configuración recomendada, porque cada uno cubre los puntos ciegos del otro: el navegador capta eventos que un servidor podría perderse, el servidor capta eventos que un bloqueador de anuncios o una cookie truncada eliminan en el navegador.

Tabla de emparejamiento: eventos del navegador y del servidor emparejados por una clave compartida; un evento sin pareja marcado

El problema es que ahora Meta tiene dos registros de una sola compra. La deduplicación es el mecanismo que los vuelve a fundir en uno. Cuando funciona, obtienes la cobertura de dos fuentes y el recuento de una. Cuando falla, obtienes el recuento de dos, y todas las cifras posteriores —volumen de conversiones, coste por compra, ROAS— están equivocadas en la dirección que hace que las malas campañas parezcan buenas.

La deduplicación no es magia automática. Es una coincidencia entre claves que tú eres responsable de configurar correctamente.

¿En qué se basa Meta para deduplicar eventos de Pixel y CAPI?

El método principal de deduplicación de Meta compara dos campos entre el evento del navegador y el del servidor:

  • event_id: un identificador único del evento concreto. En el Pixel se pasa como eventID; en el payload de la Conversions API es el campo event_id. El mismo valor, dos grafías distintas.
  • event_name: el evento estándar, por ejemplo Purchase. El event del Pixel debe ser igual al event_name de la Conversions API.

Si un evento del navegador y uno del servidor comparten el mismo event_id y el mismo event_name, y Meta recibe el segundo dentro de las 48 horas siguientes al primero, se tratan como un solo evento. Según la documentación de Meta, el emparejamiento es por event id y event name juntos: uno sin el otro no vale.

Esto es lo que ocurre realmente en cada caso de fallo:

  • El event_id difiere entre las dos fuentes. No hay coincidencia. Meta registra dos conversiones. Una compra se convierte en dos.
  • El event_id se regenera en cada carga de página. El navegador y el servidor nunca llevan el mismo valor a la vez, así que nada coincide. Es el bug autoinfligido más común.
  • Falta el event_id en una de las partes. No hay nada con lo que emparejar. Cuentan los dos.
  • El event_name difiere (Purchase frente a purchase). Los identificadores pueden coincidir perfectamente y aun así falla, porque el nombre forma parte de la clave.
  • El segundo evento llega pasadas 48 horas. Fuera de la ventana, Meta ya dio por cerrado el primero; el gemelo tardío cuenta por su cuenta.

La consecuencia de negocio tiene siempre la misma forma: un recuento de conversiones inflado alimenta un ROAS inflado. Una campaña que reporta un ROAS de 4.0 mientras duplica el recuento en realidad va a 2.0. La escalas porque el panel dice que gana, y viertes presupuesto en una campaña que, en el mejor de los casos, empata. Los eventos duplicados no solo añaden ruido: premian activamente tus peores decisiones.

¿Por qué se dispara dos veces el evento Purchase de Meta en Shopify?

En Shopify, la duplicación rara vez viene de una única etiqueta mal configurada. Viene de dos sistemas que creen ser dueños del evento Purchase y no saben el uno del otro. Las combinaciones recurrentes:

  • Canal nativo de Facebook e Instagram + una CAPI vía GTM o app. El canal nativo envía sus propios eventos de navegador y de servidor. Añade una segunda ruta de servidor mediante GTM o una app y ya tienes dos eventos Purchase por pedido sin identificador compartido.
  • Una app de CAPI + el Pixel del tema o de Customer Events. La app envía Purchase desde el servidor, el Pixel de la tienda envía Purchase desde el navegador, y la app genera sus propios identificadores que el Pixel nunca ve.
  • Dos apps de CAPI instaladas a la vez, a menudo un residuo de una configuración anterior que nunca se desinstaló. Las dos disparan; ninguna coordina.
  • Pixel de checkout.liquid + Pixel de Customer Events durante una migración a medias hacia checkout extensibility, ambos supervivientes en la página de agradecimiento.

El hilo conductor: cada fuente puede ser correcta por separado y la combinación sigue duplicando tus datos, porque la deduplicación solo funciona cuando las fuentes coinciden en event_id. Dos fuentes bien portadas que nunca intercambian identificadores son peores que una, porque parecen completas mientras cuentan el doble en silencio. Si estás desenredando qué fuentes están activas, el diagnóstico de deduplicación de Meta CAPI recorre el inventario paso a paso.

Árbol de decisión de diagnóstico

Lo que ves en Events ManagerCausa probableQué está ocurriendoSolución
Dos filas Purchase por pedido, ambas «Processed», sin etiqueta «Deduplicated»Dos fuentes sin identificador compartidoevent_id ausente o distinto en cada unaEnruta ambas por una sola fuente de identificador; pasa el mismo valor al Pixel y al servidor
Las parejas coinciden en Test Events pero el recuento en producción sigue siendo ~2× los pedidosevent_id regenerado por carga de páginaLos identificadores coinciden solo dentro de una misma carga, no entre navegador y servidorDeriva event_id del id del pedido, no de Date.now() ni de un UUID nuevo
Los eventos de servidor cuentan por separado; los de navegador parecen correctosDesajuste de event_nameEl servidor envía purchase/PURCHASE, el Pixel envía PurchaseUnifica en Purchase (distingue mayúsculas) en ambos lados
Algunos pedidos se deduplican y otros noCarrera fuera de la ventana de 48 horas, o reintentos intermitentes del servidor con identificadores nuevosEl gemelo tardío o recodificado cae fuera del emparejamientoEstabiliza el identificador; asegúrate de que el servidor envía con prontitud
Las cifras cuadran en agregado pero el EMQ es bajoNo es un problema de deduplicaciónLa deduplicación está bien; el enriquecimiento de datos de usuario es escasoEs otro asunto: consulta event match quality

¿Cómo inspecciono la deduplicación en Events Manager?

No puedes diagnosticar esto desde el panel principal: muestra totales, y los totales ocultan el doble recuento. Ve a la fuente de eventos y abre Test Events:

  1. En Events Manager, selecciona tu dataset (Pixel), abre la pestaña Test Events y copia el código de prueba.
  2. Dispara una compra de prueba real (o usa el código de evento de prueba en el campo test_event_code de tu payload de servidor para que aparezca también el evento de servidor).
  3. Observa el feed en directo. Un evento emparejado correctamente aparece con un indicador «Deduplicated», y al desplegarlo se ve que se recibió desde Browser y desde Server con el mismo event_id.
  4. Si en cambio ves dos entradas Purchase separadas —una de Browser y otra de Server— sin etiqueta de deduplicación, tus identificadores o nombres no coinciden.
  5. Para datos históricos, abre un evento individual en Overview/el detalle del evento y comprueba el connection method. Un emparejamiento sano reporta tanto navegador como servidor; dos filas independientes por pedido son la señal.

La señal que buscas es la etiqueta literal «Deduplicated» en una pareja navegador+servidor. Su ausencia, cuando estás enviando ambas, es el bug.

Un esquema de implementación correcto

Toda la solución es una idea: genera el event_id una sola vez, ligado al pedido, y entrega exactamente la misma cadena al Pixel y al servidor. Este es un esquema técnicamente correcto.

Navegador (Pixel de Customer Events o del tema), pasando eventID como cuarto argumento a fbq:

// One id per purchase, derived from the order so it is identical on the server.
// NOT Date.now(), NOT a fresh crypto.randomUUID() on each load.
const eventId = `purchase_${order.id}`; // e.g. "purchase_4512890"

fbq('track', 'Purchase', {
  value: 129.00,
  currency: 'USD',
  contents: [{ id: 'SKU-123', quantity: 1 }],
  content_type: 'product'
}, { eventID: eventId });

Servidor (payload de la Conversions API), usando el mismo valor en el campo event_id en snake_case y el mismo event_name:

{
  "data": [
    {
      "event_name": "Purchase",
      "event_time": 1690000000,
      "event_id": "purchase_4512890",
      "action_source": "website",
      "event_source_url": "https://store.example/checkout/thank-you",
      "user_data": {
        "em": ["<sha256 of lowercased, trimmed email>"],
        "fbp": "fb.1.1690000000.1234567890",
        "fbc": "fb.1.1690000000.AbCdEfGh"
      },
      "custom_data": { "value": 129.00, "currency": "USD" }
    }
  ]
}

Tres detalles hacen todo el trabajo: las cadenas event_id son idénticas byte a byte, los nombres de evento son ambos exactamente Purchase (las mayúsculas importan) y el identificador se deriva del pedido para que una recarga de página no pueda cambiarlo. Los campos fbp/fbc/em mejoran la calidad de emparejamiento, pero no son lo que deduplica: eso es solo event_id + event_name.

Cómo verifico esto en implementaciones reales

Divulgación: me dedico a construir pipelines server-side y soy el fundador de Fixel Pixel, así que tengo un sesgo hacia las configuraciones server-side; y precisamente por eso verifico la deduplicación con recuentos, no con afirmaciones.

Mi protocolo en cada proyecto de CAPI:

  1. Inventario primero de todas las fuentes. Antes de tocar código, hago una lista de todos los sistemas que pueden disparar Purchase: el canal nativo de Facebook, cualquier app de CAPI, GTM web, server GTM, los píxeles del tema. La duplicación casi siempre es una fuente extra que nadie recordaba, no una etiqueta rota.
  2. Ejecución en paralelo y lectura de Test Events, no del panel. Disparo una compra real con un test_event_code en el servidor para que aparezcan los dos gemelos y luego confirmo la etiqueta literal «Deduplicated» en la pareja emparejada.
  3. Conciliar recuentos con pedidos. Para una ventana fija comparo el recuento de Purchase que reporta Meta con el número real de pedidos de Shopify. Una configuración sana se acerca a 1:1; un recuento situado cerca de 2× los pedidos es la huella de un fallo de deduplicación aunque los eventos de prueba individuales se vean bien.
  4. Confirmar que el identificador es estable. Recargo la página de agradecimiento y vuelvo a disparar para asegurarme de que el event_id no cambia entre cargas. Si cambia, la deduplicación en producción fallará aunque una única prueba limpia haya pasado.

El paso de conciliación es el que la gente se salta, y es el único que detecta la duplicación intermitente.

Modos de fallo habituales

  • Identificadores regenerados en cada carga de página. event_id construido con Date.now(), Math.random() o un UUID nuevo en el render. Cada carga produce un valor nuevo, así que el gemelo del servidor nunca coincide. Dérivalo del pedido.
  • El dilema id-de-pedido frente a uuid-aleatorio. Un identificador derivado del pedido es estable y gratuito de reproducir en el servidor, pero es adivinable y se repite si el mismo pedido se vuelve a renderizar; normalmente está bien para la deduplicación. Un UUID aleatorio es inadivinable, pero solo funciona si lo generas una vez y lo persistes para que ambas partes lean el valor idéntico; generado dos veces, garantiza la duplicación. En la mayoría de configuraciones de Shopify es más seguro el identificador derivado del pedido.
  • Deriva de mayúsculas y nombres. purchase frente a Purchase, o un evento personalizado en un lado y un evento estándar en el otro.
  • Confusión camelCase/snake_case. eventID en el Pixel, event_id en el payload del servidor. Enviar event_id a fbq (o eventID en el JSON del servidor) no hace nada, en silencio.
  • La ventana de 48 horas. Envíos de servidor por lotes o retrasados que aterrizan más de 48 horas después del evento del navegador no se deduplicarán.
  • Apps desinstaladas que siguen disparando. Una app eliminada cuyo snippet de píxel o webhook sobrevive en el tema.

Limitaciones

La deduplicación solo reconcilia el mismo evento descrito dos veces. No fusiona eventos genuinamente distintos y no rescatará una configuración en la que las dos fuentes describen cosas diferentes (por ejemplo, el navegador dispara en la página de agradecimiento mientras el servidor dispara en la captura del pago con un identificador distinto: esos son dos eventos, contados correctamente).

Además está acotada a Meta; dejar Meta limpio no hace nada por GA4 o Google Ads, que tienen sus propias reglas de recuento. Y una tasa de deduplicación perfecta no dice nada sobre la calidad de emparejamiento: puedes deduplicar impecablemente mientras envías eventos que Meta apenas puede atribuir. La deduplicación consiste en contar una vez; el emparejamiento es una disciplina aparte.

Alternativas

Si no puedes pasar un event_id compartido —por ejemplo, una app cerrada que no lo expone—, el mecanismo de reserva de Meta empareja por fbp o external_id más event_name, pero solo cuando el evento del navegador llega primero y ambas partes llevan el identificador de forma coherente. Trátalo como una red de seguridad, no como un plan.

La alternativa más duradera es arquitectónica: consolidar en una ruta de servidor, de modo que haya un único lugar dueño del identificador, y luego dejar que el Pixel del navegador lo replique. Normalmente forma parte de una configuración más amplia de tracking server-side o de Meta Conversions API, y por eso prefiero en general un solo pipeline bien instrumentado antes que tres a medio coordinar. La mecánica de ese pipeline se cubre en Tracking server-side: beneficios, límites y arquitectura.

¿Necesitas ayuda para comprobar Purchase en Meta?

Usa esta descripción para solicitar una revisión de las fuentes y los identificadores de evento. El siguiente paso es establecer qué se puede verificar y acordar cualquier trabajo de implementación. No necesitas elegir primero otra app de CAPI.

Completa lo que sepas y deja indicado lo que desconoces. No incluyas tokens de acceso, datos de clientes ni payloads completos. Acordamos alcance y precio antes de empezar el trabajo de pago.

Se abre un borrador editable. Revisas el resumen antes de enviarlo.

Abrir Task sin transferir esta descripción ↗

Si la guía no lo resolvióEUR 375

Hago esta conciliación en tu tienda en solo lectura, por EUR 375 — veredicto por escrito dos días laborables después del kickoff.

Solicitar un Health Check

Preguntas

Preguntas que responde esta guía

¿event_id debe ser el id del pedido de Shopify o un UUID aleatorio?

Es preferible un valor derivado del id del pedido. Es el mismo en el navegador y en el servidor sin que tengas que pasar un token entre ambos, y se mantiene estable si la página de agradecimiento se recarga. Un UUID aleatorio solo funciona si lo generas una vez y compartes exactamente la misma cadena con las dos partes; en el momento en que cualquiera de las dos lo regenere, la deduplicación se rompe.

Mis eventos aparecen como «Processed» pero nunca como «Deduplicated». ¿Es malo?

Sí, si estás enviando la misma conversión desde el navegador y desde el servidor. «Deduplicated» es la etiqueta que quieres ver en una pareja emparejada. Si ambos gemelos muestran solo «Processed», Meta los está contando por separado, lo que duplica el recuento de compras e infla el ROAS.

¿De verdad tiene que coincidir también el event_name?

Sí. Meta empareja por event_id y event_name juntos. Un «Purchase» del navegador y un «purchase» o «PURCHASE» del servidor no se deduplicarán porque los nombres difieren. Los nombres de eventos estándar distinguen mayúsculas y minúsculas; envía «Purchase» en ambos lados.

¿fbp o external_id me deduplicarán si omito event_id?

Parcialmente y de forma poco fiable. Meta puede recurrir a emparejar por fbp o external_id más event_name, pero solo cuando el evento del navegador llega primero y ambas partes llevan el mismo identificador de forma coherente. Es una red de seguridad, no un diseño. Envía un event_id compartido.

Uso una app de CAPI de $9/month y el canal nativo de Facebook. ¿Estoy disparando dos veces?

Muy probablemente. Los dos envían Purchase y, a menos que coordinen un event_id compartido —cosa que la mayoría de las combinaciones de app más canal nativo no hacen—, Meta recibe dos eventos Purchase sin emparejar por pedido. Elige una sola ruta de servidor y asegúrate de que comparta identificadores con el píxel del navegador.

Daniil Maximkin

Hola, soy Daniil.

Trabajo contigo desde la definición del problema hasta la implementación y la entrega. Hablas con quien hace el trabajo. Trabajo en inglés y ruso.

¿Lo has intentado y sigues atascado?

Describe tu tarea

La primera respuesta es gratis, en un día laborable. O escribe directamente: next@taskfordaniel.com