Analítica móvil

Cómo configurar y almacenar postbacks de instalaciones y eventos en AppsFlyer

AppsFlyer es, sin duda, uno de los sistemas de tracking de referencia en el panorama mobile actual. Bien configurado, nos permite tener un seguimiento en tiempo real de los clics, instalaciones y eventos in-app que generamos con nuestras campañas. Si, además, configuramos y lanzamos eventos de conversión en la aplicación, podemos tener también métricas de retorno de inversión (ROI) por campaña.

Cómo almacenar los Postbacks de AppsFlyer en tu base de datos

Logo AppsFlyer

Sin embargo, los dashboards que genera AppsFlyer pueden ser poco claros o, en ocasiones, nos puede pasar que no obtenemos toda la información que nos interesaría, cuando sabemos a ciencia cierta que AppsFlyer dispone de ella. Este problema se puede resolver en parte utilizando la API de exportación en CSV de la que disponen (denominada Data Export – Pull APIs). Si usamos esta opción, nos encontramos con los siguientes inconvenientes:

  • AppsFlyer no garantiza que vayamos a obtener información superior a 60 días para instalaciones o 7 días para eventos in-app.
  • Nos limitan el número de peticiones que podemos hacer a la API, por lo que no podemos tener información en tiempo real.
  • Las peticiones están limitadas a un máximo de 200.000 líneas.
dashboard-appsflyer
Dashboard de AppsFlyer

Para buscar una solución flexible que nos permita obtener toda la información completa y en tiempo real, tenemos que usar lo que ellos denominan la Push API. Es lo que comúnmente podemos encontrar en otras plataformas bajo la denominación Postback, Server to Server, Postback S2S o similares. Básicamente, consiste en que cuando AppsFlyer recibe algún tipo de información de instalación o de evento in-app, se la envía automáticamente a la URL que le indiquemos mediante una petición POST, en cuyo cuerpo viene un JSON con toda la info detallada.

La información es poder

Pero… ¿de qué información estamos hablando? Pues de toda la que podamos imaginar. Desde información de la campaña de adquisición, horas de clics e instalaciones, información del dispositivo, parámetros ad_subX, etc. En total, a día de hoy, son 65 variables distintas que pueden estar disponibles, o no, en función del tipo de evento (instalación o evento in-app), del tipo de instalación (orgánica o no orgánica) y del sistema operativo (iOS o Android). Puedes ver en AppsFlyer el detalle de cada uno de los campos disponibles para iOS y para Android. Toda esta info nos puede ayudar muchísimo a optimizar campañas y analizar métricas de nuestro negocio, por lo que vamos a guardarla en nuestros sistemas para que podamos interactuar con ella cuando lo estimemos oportuno.

Ya tenemos claro que tenemos una información útil disponible y que queremos almacenarla en nuestros servidores. Pero, ¿cómo demonios se hace esto? En PickASO hemos preparado esta pequeña guía paso a paso para que puedas hacérsela llegar a tus desarrolladores. En ella explicamos cómo hacerlo utilizando el lenguaje PHP y almacenando los valores en una base de datos MySQL. Sin embargo, la metodología sería la misma o muy parecida independientemente del lenguaje de programación.

PHP y MySQL para almacenar datos de AppsFlyer

Para empezar, conviene descargar este fichero .ZIP donde podrás encontrar tanto el código PHP como el SQL de la tabla que crearemos para almacenar los datos.

El primer paso sería crear la base de datos MySQL e importar el fichero que define la tabla events en la que almacenaremos toda la información. Para simplificar el sistema, hemos unido todos los datos de iOS y Android en una misma tabla. Como AppsFlyer no da mucha información sobre el tipo de datos de los campos, asumimos que todos ellos son de texto (VARCHAR) excepto las fechas que serán DATETIME. Si pones esto en producción y vas a manejar gran cantidad de datos, te recomendamos que optimices los tipos de datos y crees índices en la tabla en aquellos campos por los que vayas a hacer consultas:

CREATE TABLE IF NOT EXISTS `events` (    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,    `advertising_id` VARCHAR(255) NULL ,    `af_ad` VARCHAR(255) NULL ,    `af_ad_id` VARCHAR(255) NULL ,    `af_ad_type` VARCHAR(255) NULL ,    `af_adset` VARCHAR(255) NULL ,    `af_adset_id` VARCHAR(255) NULL ,    `af_c_id` VARCHAR(255) NULL ,    `af_channel` VARCHAR(255) NULL ,    `af_cost_currency` VARCHAR(255) NULL ,    `af_cost_model` VARCHAR(255) NULL ,    `af_cost_value` VARCHAR(255) NULL ,    `af_keywords` VARCHAR(255) NULL ,    `af_siteid` VARCHAR(255) NULL ,    `af_sub1` VARCHAR(255) NULL ,    `af_sub2` VARCHAR(255) NULL ,    `af_sub3` VARCHAR(255) NULL ,    `af_sub4` VARCHAR(255) NULL ,    `af_sub5` VARCHAR(255) NULL ,    `agency` VARCHAR(255) NULL ,    `android_id` VARCHAR(255) NULL ,    `app_id` VARCHAR(255) NULL ,    `app_name` VARCHAR(255) NULL ,    `app_version` VARCHAR(255) NULL ,    `appsflyer_device_id` VARCHAR(255) NULL ,    `attribution_type` VARCHAR(255) NULL ,    `campaign` VARCHAR(255) NULL ,    `carrier` VARCHAR(255) NULL ,    `city` VARCHAR(255) NULL ,    `click_time` DATETIME NULL ,    `click_url` VARCHAR(255) NULL ,    `cost_per_install` VARCHAR(255) NULL ,    `country_code` VARCHAR(255) NULL ,    `currency` VARCHAR(255) NULL ,    `customer_user_id` VARCHAR(255) NULL ,    `device_brand` VARCHAR(255) NULL ,    `device_model` VARCHAR(255) NULL ,    `device_name` VARCHAR(255) NULL ,    `device_type` VARCHAR(255) NULL ,    `download_time` DATETIME NULL ,    `event_name` VARCHAR(255) NULL ,    `event_time` DATETIME NULL ,    `event_type` VARCHAR(255) NULL ,    `event_value` VARCHAR(255) NULL ,    `fb_adgroup_id` VARCHAR(255) NULL ,    `fb_adgroup_name` VARCHAR(255) NULL ,    `fb_adset_id` VARCHAR(255) NULL ,    `fb_adset_name` VARCHAR(255) NULL ,    `fb_campaign_id` VARCHAR(255) NULL ,    `fb_campaign_name` VARCHAR(255) NULL ,    `http_referrer` VARCHAR(255) NULL ,    `imei` VARCHAR(255) NULL ,    `idfa` VARCHAR(255) NULL ,    `idfv` VARCHAR(255) NULL ,    `install_time` DATETIME NULL ,    `ip` VARCHAR(255) NULL ,    `is_retargeting` VARCHAR(255) NULL ,    `language` VARCHAR(255) NULL ,    `mac` VARCHAR(255) NULL ,    `media_source` VARCHAR(255) NULL ,    `operator` VARCHAR(255) NULL ,    `os_version` VARCHAR(255) NULL ,    `platform` VARCHAR(255) NULL ,    `re_targeting_conversion_type` VARCHAR(255) NULL ,    `sdk_version` VARCHAR(255) NULL ,    `wifi` VARCHAR(255) NULL ,    PRIMARY KEY (`id`) )  ENGINE = InnoDB;  

A continuación, vamos con el fichero PHP que recibirá la notificación y la almacenará en la BBDD. Lo primero que vamos a hacer es comprobar que la petición viene de una IP de las que aparecen en la lista de AppsFlyer, para evitar que algún usuario mal intencionado nos provoque problemas:

$valid_ips = array(  "54.73.22.68","54.72.160.117","54.217.174.42","54.195.225.209","54.77.45.90","54.77.178.93","54.228.23.208"  );    // Check IP  $ip = NULL;  if(isset($_SERVER)) {  	if (!empty($_SERVER['HTTP_CLIENT_IP'])){  		$ip = $_SERVER['HTTP_CLIENT_IP'];  	}  	elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {  		$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];  	} else {  		$ip = $_SERVER['REMOTE_ADDR'];  	}  }  if(!in_array($ip,$valid_ips)){  	header("HTTP/1.1 403 Forbidden");  	echo "Invalid IP: ".$ip;  	exit();  }

Después, definiremos los credenciales de acceso a la BBDD y conectaremos con ella.

// MySQL Connection Config  $server = "localhost";  $user = "";  $password = "";  $db = "";  $port = "3306";  $table = "events";    // Connect to MySQL database  $mysqli = new mysqli($server, $user, $password, $db, $port);  if(mysqli_connect_errno()) {  	header("HTTP/1.1 500 Internal Server Error");  	echo "Error connecting to database: ". mysqli_connect_error();  	exit();  }

AppsFlyer nos va a pasar la información mediante el cuerpo de la petición POST. Dicha info la tenemos en php://input, por lo que la cogemos de ahí y convertimos la cadena de texto en un array que podamos manipular después.

// GET Appsflyer JSON from POST body and convert it to an array  $json = file_get_contents('php://input');  $json = json_decode($json,true);

AppsFlyer también nos avisa que el formato del JSON puede variar entre versiones, por lo que definimos un listado de campos que tenemos en la base de datos y que comprobaremos si vienen en la petición.

// Valid fields (updated 2015-11-18, last checked 2016-01-08)  // http://support.appsflyer.com/entries/59865879-Push-API-Data-Structure-iOS  // http://support.appsflyer.com/entries/60148305-Push-API-Data-Structure-Android  $valid_fields = array(  	"advertising_id", "af_ad", "af_ad_id", "af_ad_type", "af_adset", "af_adset_id", "af_c_id", "af_channel", "af_cost_currency", "af_cost_model", "af_cost_value", "af_keywords", "af_siteid", "af_sub1", "af_sub2", "af_sub3", "af_sub4", "af_sub5", "agency", "android_id", "app_id", "app_name", "app_version", "appsflyer_device_id", "attribution_type", "campaign", "carrier", "city", "click_time", "click_url", "cost_per_install", "country_code", "currency", "customer_user_id", "device_brand", "device_model", "device_name", "device_type", "download_time", "event_name", "event_time", "event_type", "event_value", "fb_adgroup_id", "fb_adgroup_name", "fb_adset_id", "fb_adset_name", "fb_campaign_id", "fb_campaign_name", "http_referrer", "imei", "idfa", "idfv", "install_time", "ip", "is_retargeting", "language", "mac", "media_source", "operator", "os_version", "platform", "re_targeting_conversion_type", "sdk_version", "wifi");    // Complete the data array with all the fields  $data = array();  foreach($valid_fields as $field){  	if(array_key_exists($field, $json)){  		$data[$field] = $mysqli->real_escape_string($json[$field]);  	}  	else {  		$data[$field] = NULL;  	}  }

Finalmente, tenemos que generar una sentencia INSERT con toda esta información y ejecutarla para que toda la información acabe guardada en nuestra base de datos:

// Generate SQL and execute query  $columns = implode(", ",array_keys($data));  $values  = implode("', '", array_values($data));  $sql = "INSERT INTO $table ($columns) VALUES ('$values')";  $mysqli->query($sql);

Si todo ha ido bien, ya tenemos un fichero PHP que recibe la petición POST de AppsFlyer y que la almacena en la base de datos. Ahora queda subirla al servidor y apuntarnos la URL.

Para terminar, tenemos que indicarle a AppsFlyer que debe hacernos los postbacks a la URL que hemos apuntado en el párrafo anterior. Para ello, tenemos que seleccionar nuestra aplicación en el panel de control y pulsar en Integration -> API Access. Al comienzo están los ejemplos de uso de la API de exportación y justo después veremos una sección denominada Push API. Ahí es donde debemos pegar la URL y activar todas las notificaciones que nos interesen. Para guardar los cambios pulsamos en el botón Save.

Configuración Postback AppsFlyer

Para finalizar, podemos comprobar que todo funciona bien pulsando el botón Send Test Data. Si el script nos devuelve un código 200 en verde será que hemos hecho todos los pasos correctamente y que ya tenemos nuestro sistema funcionando. Podemos hacer una última comprobación con la base de datos para ver que nuestra información está ahí.

Ahora ya sólo queda que encuentres la mejor manera de consumir toda la información y sacar conclusiones para mejorar tus métricas.

Guardar información de AppsFlyer en nuestro sistema nos permitirá disponer de toda la información necesaria para optimizar nuestras campañas de App Marketing y analizar métricas de nuestro negocio móvil.

¿Has almacenado correctamente los postsbacks / data de AppsFlyer en tu base de datos? ¡Cuéntanos en los comentarios!

Sitio web oficial | AppsFlyer

Rubén Baquero
Rubén Baquero

3 comentarios en «Cómo configurar y almacenar postbacks de instalaciones y eventos en AppsFlyer»

  1. Hola,
    Primero, gracias por el artículo me ayudo a configurar todo.
    Segundo, recientemente dejaron de registrarse los eventos, era debido a que se enviaban nuevos atributos. Dejo a continuación los que he añadido por si a alguien le ayuda.

    ALTER TABLE `events`
    ADD COLUMN `click_time_selected_timezone` VARCHAR(255) NULL,
    ADD COLUMN `download_time_selected_timezone` VARCHAR(255) NULL,
    ADD COLUMN `install_time_selected_timezone` VARCHAR(255) NULL,
    ADD COLUMN `event_time_selected_timezone` VARCHAR(255) NULL,
    ADD COLUMN `selected_currency` VARCHAR(255) NULL,
    ADD COLUMN `revenue_in_selected_currency` VARCHAR(255) NULL
    ;

    Responder
  2. Hey, I miss understand this part in the code:
    // GET Appsflyer JSON from POST body and convert it to an array
    $json = file_get_contents(‘php://input’);
    $json = json_decode($json,true);

    Till now I used the static csv download and upload every day,
    I still don’t understand how do i replace it? how it should running? the script need to ‘live’ always and register new events?

    the file_get_contents(‘php://input’); ??! what is that? I guess it’s the address where the event come from?
    How do I find it?

    Responder
    • Hi Benny,

      Appsflyer is sending the info in the POST body as a JSON string. What you do with that lines is to read the body of the request from php:://input and decode it from a JSON string to a PHP array.

      The script must be available online and appsflyer sends a request to it everytime an install is made

      Responder
Deja un comentario