AppsFlyer Integration

Connect AppsFlyer to RELO's data backbone. Automated event ingestion, partner attribution, and revenue tracking.

Integracion con AppsFlyer

Conecta AppsFlyer al backbone de datos de RELO. Ingesta automatizada de eventos, atribucion de partners y seguimiento de ingresos.

Pull API (Recommended) Pull API (Recomendado) S2S Postback 60-min Sync Sync cada 60 min Auto Attribution Atribucion Automatica

Contents

Contenido

  1. 01 OverviewVision General
  2. 02 Pull API IntegrationIntegracion Pull API
  3. 03 S2S Postback IntegrationIntegracion S2S Postback
  4. 04 Event TypesTipos de Eventos
  5. 05 Attribution & Partner MatchingAtribucion y Matching de Partners
  6. 06 Revenue CalculationCalculo de Revenue
  7. 07 Primary Attribution FilterFiltro de Atribucion Primaria
  8. 08 Setup StepsPasos de Configuracion
  9. 09 Data Field MappingMapeo de Campos
  10. 10 TroubleshootingSolucion de Problemas

Overview

RELO receives AppsFlyer data through two methods. Both feed into the same Go ingest service, which writes events to ClickHouse for analytics and syncs aggregates to Supabase for the dashboard.

Vision General

RELO recibe datos de AppsFlyer a traves de dos metodos. Ambos alimentan el mismo servicio de ingesta en Go, que escribe eventos en ClickHouse para analitica y sincroniza agregados a Supabase para el dashboard.

🔃

Pull API

Pull API

RELO's Go service automatically polls AppsFlyer's Pull API every 60 minutes. No configuration needed on the AppsFlyer side beyond enabling API access. This is the primary and recommended method.

El servicio Go de RELO consulta automaticamente la Pull API de AppsFlyer cada 60 minutos. No requiere configuracion del lado de AppsFlyer mas alla del acceso a la API. Este es el metodo principal y recomendado.

Recommended Recomendado
📨

S2S Postback

S2S Postback

AppsFlyer sends real-time postbacks to RELO's endpoint for each event. Lower latency but requires per-media-source configuration in your AppsFlyer account.

AppsFlyer envia postbacks en tiempo real al endpoint de RELO por cada evento. Menor latencia pero requiere configuracion por media source en tu cuenta de AppsFlyer.

Alternative Alternativa
📊

AppsFlyer

Installs, purchases, in-app events

Instalaciones, compras, eventos in-app

↓ ↓
🔃

Pull API (every 60 min)

Pull API (cada 60 min)

RELO polls automatically

RELO consulta automaticamente

📨

S2S Postback (real-time)

S2S Postback (tiempo real)

s2s.relo.mx → ingest.relo.mx

Go Ingest Service

Servicio de Ingesta (Go)

Attribution matching, fraud scoring, identity resolution

Matching de atribucion, scoring de fraude, resolucion de identidad

↓ ↓
🗃

ClickHouse

Analytics engine, raw events, 24-month TTL

Motor de analitica, eventos raw, TTL de 24 meses

📂

Supabase

Daily aggregates, dashboard, partner config

Agregados diarios, dashboard, config de partners

Pull API Integration

The recommended method. RELO's Go service runs a systemd timer that polls AppsFlyer's Pull API every 60 minutes, fetching new installs and in-app events.

Integracion Pull API

El metodo recomendado. El servicio Go de RELO ejecuta un timer de systemd que consulta la Pull API de AppsFlyer cada 60 minutos, obteniendo nuevas instalaciones y eventos in-app.

Fully Automated

Completamente Automatico

Once your App ID and API Token are configured in RELO, data flows automatically. No manual CSV uploads or webhook configuration required.

Una vez que tu App ID y API Token estan configurados en RELO, los datos fluyen automaticamente. No se requieren cargas manuales de CSV ni configuracion de webhooks.

How It Works

Como Funciona

AspectAspecto DetailDetalle
FrequencyFrecuencia Every 60 minutes (systemd timer)Cada 60 minutos (timer de systemd)
Data ScopeAlcance Installs, in-app events (purchases, add-to-cart, registrations, custom)Instalaciones, eventos in-app (compras, agregar al carrito, registros, custom)
DeduplicationDeduplicacion By event_id (ULID). Re-pulls of the same time window are safe.Por event_id (ULID). Re-consultar la misma ventana de tiempo es seguro.
Primary AttributionAtribucion Primaria Only events with Is Primary Attribution = true are processedSolo se procesan eventos con Is Primary Attribution = true
RequirementsRequisitos AppsFlyer App ID and API Token configured in RELOApp ID y API Token de AppsFlyer configurados en RELO

Latency

Latencia

Events typically appear in the RELO dashboard within 60-120 minutes of occurring. The Pull API window overlaps slightly to ensure no events are missed.

Los eventos tipicamente aparecen en el dashboard de RELO dentro de 60-120 minutos de ocurrir. La ventana de la Pull API se superpone ligeramente para no perder eventos.

S2S Postback Integration

An alternative method where AppsFlyer pushes events in real-time to RELO's postback endpoint. Lower latency but requires per-media-source configuration in your AppsFlyer account.

Integracion S2S Postback

Un metodo alternativo donde AppsFlyer envia eventos en tiempo real al endpoint de postback de RELO. Menor latencia pero requiere configuracion por media source en tu cuenta de AppsFlyer.

Endpoint

ENDPOINT
POST https://s2s.relo.mx/v1/postback/appsflyer

// Proxied through Cloudflare Worker to:
// https://ingest.relo.mx/postback/appsflyer (Go ingest service)

Authentication

Autenticacion

RELO verifies the HMAC signature sent by AppsFlyer in the X-AF-Signature header. This ensures postbacks are genuinely from AppsFlyer and have not been tampered with.

RELO verifica la firma HMAC enviada por AppsFlyer en el header X-AF-Signature. Esto asegura que los postbacks son genuinos de AppsFlyer y no han sido manipulados.

Payload Format

Formato del Payload

JSON
{
  "event_name": "af_purchase",
  "event_time": "2026-03-10 14:30:00.000",
  "appsflyer_id": "1709654321000-1234567",
  "media_source": "affiliate_relo",
  "campaign": "mx_pd_affiliate_relo_none_always-on_sub1",
  "adset": "banner_none",
  "ad": "SAM-MX-A1B2C3",
  "event_revenue": 17703.40,
  "event_revenue_currency": "MXN",
  "event_value": "{\"af_order_id\":\"MX260310-12345\", ...}",
  "country_code": "MX",
  "city": "Ciudad de Mexico",
  "device_model": "SM-S928B",
  "is_primary_attribution": true,
  "is_retargeting": false
}

Event Types

AppsFlyer events are mapped to RELO's Universal Event Schema. The Go ingest service normalizes all events into a consistent 35-field format stored in ClickHouse.

Tipos de Eventos

Los eventos de AppsFlyer se mapean al Esquema Universal de Eventos de RELO. El servicio de ingesta normaliza todos los eventos a un formato consistente de 35 campos en ClickHouse.

AppsFlyer Event RELO event_type DescriptionDescripcion
install install App installation. Tracked for identity graph and funnel analysis. Instalacion de app. Rastreado para grafo de identidad y analisis de funnel.
af_purchase purchase Primary conversion event. Contains order ID, products, revenue. Used for partner commissions. Evento de conversion principal. Contiene order ID, productos, revenue. Usado para comisiones de partners.
af_add_to_cart engagement Cart addition. Used for retargeting audiences and funnel analysis. Adicion al carrito. Usado para audiencias de retargeting y analisis de funnel.
af_complete_registration custom Registration event. Tracked for partner quality metrics. Evento de registro. Rastreado para metricas de calidad de partners.
Other eventsOtros eventos custom Stored with event_type=custom and original name preserved in event_name. Almacenados con event_type=custom y nombre original preservado en event_name.

Only af_purchase generates product_sales

Solo af_purchase genera product_sales

All event types are ingested into ClickHouse's events table, but only af_purchase events are parsed into individual product records in Supabase's product_sales table. This is the data used for partner commissions and dashboards.

Todos los tipos de eventos se ingestan en la tabla events de ClickHouse, pero solo los eventos af_purchase se parsean en registros individuales de productos en la tabla product_sales de Supabase. Estos datos se usan para comisiones de partners y dashboards.

Attribution & Partner Matching

RELO attributes sales to partners by matching a configurable field from each event against attribution rules defined per partner. The first matching rule wins.

Atribucion y Matching de Partners

RELO atribuye ventas a partners comparando un campo configurable de cada evento contra reglas de atribucion definidas por partner. La primera regla que haga match gana.

How It Works

Como Funciona

Each client in RELO has an attribution_field setting (default: campaign). This determines which event field is read and compared against each partner's attribution rules.

Cada cliente en RELO tiene un campo attribution_field (default: campaign). Esto determina que campo del evento se lee y compara contra las reglas de atribucion de cada partner.

Campaign Name Format

Formato del Nombre de Campana

Partners embed their unique CID (Campaign ID) in the campaign name. RELO extracts the value from the configured field and matches it against each partner's attribution rules.

Los partners insertan su CID (Campaign ID) unico en el nombre de la campana. RELO extrae el valor del campo configurado y lo compara contra las reglas de atribucion de cada partner.

FORMAT
// Campaign name pattern:
mx_{category}_affiliate_relo_{...}_{CID}_{...}

// Example:
mx_pd_affiliate_relo_none_always-on_sub1_banner_none_conversion
                                      ^^^^
                                      Partner CID (e.g., Mobupps = sub1)

Match Types

Tipos de Match

Each partner can have multiple attribution rules, each with a match type. All matching is case-insensitive.

Cada partner puede tener multiples reglas de atribucion, cada una con un tipo de match. Todo el matching es case-insensitive.

Match TypeTipo de Match BehaviorComportamiento ExampleEjemplo
exact Full string equalityIgualdad exacta sub1 matches sub1 only
contains Substring matchMatch de subcadena relo matches mx_affiliate_relo_nov
startswith Prefix matchMatch de prefijo mx_samsung_ matches mx_samsung_affiliate
endswith Suffix matchMatch de sufijo _mobupps matches mx_relo_mobupps

Default is exact (not contains)

El default es exact (no contains)

Rules without an explicit match_type default to exact. This prevents accidental collisions like sub1 matching sub10. Use contains only when you explicitly need substring matching.

Las reglas sin un match_type explicito usan exact por defecto. Esto previene colisiones accidentales como que sub1 haga match con sub10. Usa contains solo cuando explicitamente necesites matching de subcadena.

Unmatched Events

Eventos Sin Match

Events that do not match any partner's rules are stored with partner_id = NULL. These represent organic sales or non-RELO channels. They are visible in admin dashboards for total market analysis but do not count toward partner commissions.

Los eventos que no hacen match con ninguna regla se almacenan con partner_id = NULL. Representan ventas organicas o canales no-RELO. Son visibles en dashboards de admin para analisis de mercado total pero no cuentan para comisiones de partners.

Revenue Calculation

RELO extracts per-product revenue from AppsFlyer purchase events using a strict priority order. Getting this right is critical for accurate commission calculations.

Calculo de Revenue

RELO extrae el revenue por producto de los eventos de compra de AppsFlyer usando un orden de prioridad estricto. Obtener esto correctamente es critico para calculos precisos de comisiones.

Never use af_price for revenue

Nunca usar af_price para revenue

af_price is the list price (before discounts). Event Revenue is the actual revenue after discounts. Using af_price can inflate revenue by 40-60%.

af_price es el precio de lista (antes de descuentos). Event Revenue es el revenue real despues de descuentos. Usar af_price puede inflar el revenue en 40-60%.

Revenue Priority (highest to lowest)

Prioridad de Revenue (de mayor a menor)

# SourceFuente DescriptionDescripcion
1 awin_cg Per-product revenue breakdown. Format: Category:Amount|Category:Amount. Used when the sum matches Event Revenue. Desglose de revenue por producto. Formato: Categoria:Monto|Categoria:Monto. Se usa cuando la suma coincide con Event Revenue.
2 Event Revenue Total order revenue (actual, after discounts). When awin_cg is unavailable, distributed proportionally across products by af_price. Revenue total de la orden (real, despues de descuentos). Cuando awin_cg no esta disponible, se distribuye proporcionalmente entre productos por af_price.
3 af_price List price. Last resort only, when both awin_cg and Event Revenue are missing. Precio de lista. Ultimo recurso, solo cuando faltan tanto awin_cg como Event Revenue.

Product Extraction from Event Value

Extraccion de Productos del Event Value

The Event Value field contains a JSON object with product arrays. RELO parses this to create individual product records in product_sales.

El campo Event Value contiene un objeto JSON con arreglos de productos. RELO parsea esto para crear registros individuales de productos en product_sales.

EVENT VALUE JSON
{
  "af_order_id": "MX260310-12345678",
  "af_content_id": ["SKU-001", "SKU-002"],
  "af_price": [41998.99, 5999.00],         // List prices (NOT revenue)
  "af_quantity": [1, 1],
  "af_currency": "MXN",
  "awin_cg": "Mobile_Smartphone:16984.30|Mobile_Wearable:719.10",
  "items": [
    { "af_content": "Galaxy S24 Ultra", "item_category": "Mobile_Smartphone" },
    { "af_content": "Galaxy Buds3 Pro", "item_category": "Mobile_Wearable" }
  ]
}

// Event Revenue (CSV field): 17703.40
// awin_cg sum: 16984.30 + 719.10 = 17703.40 (matches!)
// Result: use awin_cg values as exact per-product revenue

Primary Attribution Filter

A critical deduplication mechanism. AppsFlyer may report the same purchase in both User Acquisition (UA) and Retargeting (RT) data. RELO only processes the one AppsFlyer designates as primary.

Filtro de Atribucion Primaria

Un mecanismo critico de deduplicacion. AppsFlyer puede reportar la misma compra en datos de User Acquisition (UA) y Retargeting (RT). RELO solo procesa el que AppsFlyer designa como primario.

The Problem

El Problema

When a user is exposed to both a UA campaign and an RT campaign before purchasing, AppsFlyer exports the purchase event in both reports. Without filtering, the same order would be counted twice, potentially attributed to two different partners.

Cuando un usuario esta expuesto a una campana UA y una RT antes de comprar, AppsFlyer exporta el evento de compra en ambos reportes. Sin filtro, la misma orden se contaria dos veces, potencialmente atribuida a dos partners diferentes.

EXAMPLEEJEMPLO
// Same order appears in BOTH reports:

// UA Report (User Acquisition):
Order: MX260310-12345
Campaign: mx_pd_affiliate_relo_..._sub3  // Partner A
Is Primary Attribution: false          // NOT the winner

// RT Report (Retargeting):
Order: MX260310-12345
Campaign: mx_pd_affiliate_relo_..._sub1  // Partner B
Is Primary Attribution: true           // THE WINNER - only this is processed

The Solution

La Solucion

RELO checks the Is Primary Attribution field for every purchase event. Only events where this field is true are processed. This respects AppsFlyer's attribution decision and prevents double-counting.

RELO verifica el campo Is Primary Attribution para cada evento de compra. Solo se procesan los eventos donde este campo es true. Esto respeta la decision de atribucion de AppsFlyer y previene la doble contabilizacion.

Additional deduplication

Deduplicacion adicional

Beyond the primary attribution filter, RELO also deduplicates using a sale_hash (SHA-256 of order_id + product_id + quantity). Even if the same event arrives through both Pull API and S2S postback, it will only be recorded once.

Ademas del filtro de atribucion primaria, RELO deduplica por sale_hash (SHA-256 de order_id + product_id + quantity). Incluso si el mismo evento llega por Pull API y S2S postback, solo se registra una vez.

Setup Steps

Follow these steps to connect your AppsFlyer account to RELO. The Pull API method requires minimal configuration.

Pasos de Configuracion

Sigue estos pasos para conectar tu cuenta de AppsFlyer a RELO. El metodo Pull API requiere configuracion minima.

Get your RELO client_id

Obtener tu client_id de RELO

Contact your RELO account manager to get your client_id. This is the unique identifier for your brand in the RELO system.

Contacta a tu account manager de RELO para obtener tu client_id. Este es el identificador unico de tu marca en el sistema RELO.

Provide your AppsFlyer App ID and API Token

Proporcionar tu App ID y API Token de AppsFlyer

Share your AppsFlyer App ID and API Token with RELO. These credentials allow RELO's Go service to poll the Pull API on your behalf. RELO stores these securely and uses them only for data retrieval.

Comparte tu App ID y API Token de AppsFlyer con RELO. Estas credenciales permiten al servicio Go de RELO consultar la Pull API en tu nombre. RELO las almacena de forma segura y las usa solo para la obtencion de datos.

(S2S only) Configure the postback URL

(Solo S2S) Configurar la URL de postback

If using S2S postbacks, configure the following URL as your postback endpoint in your AppsFlyer account:

Si usas S2S postbacks, configura la siguiente URL como tu endpoint de postback en tu cuenta de AppsFlyer:

https://s2s.relo.mx/v1/postback/appsflyer

Verify data flow

Verificar el flujo de datos

Check the RELO dashboard to confirm events are arriving. For Pull API, data should appear within 60-120 minutes. For S2S, data appears within seconds. Use the admin dashboard's audit tab to verify event counts and attribution status.

Verifica el dashboard de RELO para confirmar que los eventos estan llegando. Para Pull API, los datos deben aparecer en 60-120 minutos. Para S2S, los datos aparecen en segundos. Usa la pestana de auditoria del dashboard de admin para verificar conteos y estado de atribucion.

Data Field Mapping

How AppsFlyer fields map to RELO's Universal Event Schema (35-field ClickHouse table).

Mapeo de Campos

Como los campos de AppsFlyer se mapean al Esquema Universal de Eventos de RELO (tabla ClickHouse de 35 campos).

AppsFlyer Field RELO Field NotesNotas
Event Name event_name Preserved as-is. Also determines event_type. Se preserva tal cual. Tambien determina event_type.
Event Time event_time DateTime64 with ms precision. DateTime64 con precision de ms.
AppsFlyer ID device_id Mapped to unified device ID via identity graph. Mapeado a ID unificado via grafo de identidad.
Media Source media_source Traffic source (LowCardinality). Fuente de trafico (LowCardinality).
Campaign campaign Campaign name containing partner CID. Nombre de campana con CID del partner.
Adset adset Ad set / ad group name. Nombre del ad set / ad group.
Ad ad Ad creative name. May contain asset tracking ID. Nombre del creativo. Puede contener tracking ID de asset.
Event Revenue revenue Per-product revenue (via awin_cg or proportional). Revenue por producto (via awin_cg o proporcional).
Event Valueaf_order_id order_id Extracted from Event Value JSON. Extraido del JSON Event Value.
Event Valueaf_content_id product_id Product SKU. One row per product. SKU del producto. Una fila por producto.
Event Valueitems[].af_content product_name Product display name. Nombre de display del producto.
Event Valueaf_quantity quantity Quantity per product. Cantidad por producto.
Country Code country_code ISO 3166-1 alpha-2
City city City name from geo data. Nombre de ciudad de datos geo.
Device Model device_model e.g., SM-S928B ej., SM-S928B
Is Retargeting UA/RT flagFlag UA/RT Determines User Acquisition vs Retargeting. Determina User Acquisition vs Retargeting.
Is Primary Attribution Filter (not stored)Filtro (no se almacena) Events where false are skipped entirely. Eventos con false se omiten completamente.
(computed)(calculado) product_line Segment code (MX, VD, DA, HA, IT, NW) from product name/category. Codigo de segmento (MX, VD, DA, HA, IT, NW) del nombre/categoria del producto.
(computed)(calculado) partner_id Matched via attribution rules. NULL if no match. Matcheado via reglas de atribucion. NULL si no hay match.
(computed)(calculado) is_fraud Fraud score 0-255 from ML model. >200 flagged, >240 blocked. Score de fraude 0-255 del modelo ML. >200 marcado, >240 bloqueado.

Troubleshooting

Common issues and their solutions when integrating AppsFlyer with RELO.

Solucion de Problemas

Problemas comunes y sus soluciones al integrar AppsFlyer con RELO.

ProblemProblema Likely CauseCausa Probable SolutionSolucion
No events in RELO No aparecen eventos en RELO App ID or API Token not configured or expired App ID o API Token no configurados o expirados Verify credentials with your RELO account manager. Check backbone health at ingest.relo.mx/health. Verifica credenciales con tu account manager de RELO. Verifica salud del backbone en ingest.relo.mx/health.
Sales not attributed to partner Ventas no atribuidas a un partner Campaign name missing the partner's CID, or rules misconfigured Nombre de campana sin el CID del partner, o reglas mal configuradas Check attribution rules in RELO admin dashboard. Verify campaign name format includes the correct CID. Try contains instead of exact if needed. Verifica reglas de atribucion en el dashboard admin de RELO. Verifica que el formato de campana incluya el CID correcto. Intenta contains en lugar de exact si es necesario.
Revenue numbers too high Numeros de revenue muy altos Using af_price (list price) instead of Event Revenue (actual) Usando af_price (precio de lista) en lugar de Event Revenue (real) Handled automatically by RELO. If inflated, contact support to verify revenue extraction for your account. Se maneja automaticamente por RELO. Si esta inflado, contacta a soporte para verificar la extraccion de revenue de tu cuenta.
Duplicate events Eventos duplicados Same event via Pull API and S2S, or missing primary attribution filter Mismo evento por Pull API y S2S, o filtro de atribucion primaria faltante RELO deduplicates by sale_hash automatically. Check audit page for duplicate order IDs. Using only Pull API is the safest approach. RELO deduplica por sale_hash automaticamente. Verifica la pagina de auditoria para order IDs duplicados. Usar solo Pull API es el enfoque mas seguro.
Wrong partner gets the sale El partner incorrecto recibe la venta Overlapping rules (e.g., sub1 with contains matches sub10) Reglas superpuestas (ej: sub1 con contains matchea sub10) Switch to exact match type for CIDs that could collide. Review conflicts in the audit page. Cambia a tipo de match exact para CIDs que podrian colisionar. Revisa conflictos en la pagina de auditoria.
Events delayed by hours Eventos retrasados por horas Normal Pull API behavior (60-min polling). AF may also have processing delays. Comportamiento normal de Pull API (polling de 60 min). AF puede tener retrasos de procesamiento. If near-real-time is needed, configure S2S postbacks as a complement. Both can run simultaneously. Si se necesita casi-tiempo-real, configura S2S postbacks como complemento. Ambos pueden funcionar simultaneamente.
S2S postbacks rejected (401) S2S postbacks rechazados (401) HMAC signature verification failed Verificacion de firma HMAC fallo Ensure the HMAC secret in your AppsFlyer account matches what RELO has. Contact your account manager to verify. Asegurate de que el secreto HMAC en tu cuenta de AppsFlyer coincida con lo que RELO tiene. Contacta a tu account manager.
Products in wrong segment Productos en segmento incorrecto Product name/category does not match segment rules. Falls to OTHER. Nombre/categoria de producto no coincide con reglas de segmento. Cae en OTHER. Review segment classification rules in RELO admin config. Add new keywords for naming conventions not yet covered. Revisa reglas de clasificacion de segmentos en config del admin de RELO. Agrega keywords para convenciones de nombres no cubiertas.
💬

Need help?

Necesitas ayuda?

Contact your RELO account manager or reach out to the engineering team. For real-time diagnostics, use the RELO admin dashboard at portal.relo.mx → Audit tab.

Contacta a tu account manager de RELO o al equipo de ingenieria. Para diagnosticos en tiempo real, usa el dashboard admin de RELO en portal.relo.mx → pestana de Auditoria.