Implementar API de conversiones de Facebook en Laravel


  • Share on Pinterest

Requisitos:

  1. Tener configurada una cuenta de facebook business
  2. Tener activado y configurado el pixel de seguimiento en la cuenta/negocio donde se quiere activar el api de conversiones.
  3. Tener implementado el pixel de seguimiento en el sitio web o aplicación.

Configurar la API de conversiones en administrador de eventos de Facebook

1. Ingresa al Administrador de eventos:

https://business.facebook.com/events_manager2

2. Clic en “Agregar eventos” y después en “Usar la API de conversiones”:

3. Clic en “Siguiente” y posteriormente en “Configurar”

4. Clic en “Instalar código manualmente”

5. Clic en continuar

6. Seleccionar el giro del negocio y los eventos que se enviarán desde la implementación de la API:

En mi caso particular:

7. Seleccionar los parámetros que se enviaran desde el servidor. Se deben enviar la mayor cantidad de parámetros posibles para que Facebook pueda deduplicar (descartar datos duplicados) en nuestras analíticas.

En mi caso enviaré solo la ip del usuario y el agente (el navegador que utiliza el usuario).

Al terminar clic en “Continuar”.

8. Clic en “Continuar” y después en “Finalizar”.

9. Después, estando de nuevo en el panel principal, clic en “Administrar integraciones” y luego en “Completar configuración”.

10. Clic en “Generar un token de acceso”

11. Clic en el botón “Generar token de acceso”

12. Para las pruebas se debe genera un código que se envía en cada petición.
Clic en “Iniciar eventos de prueba”.

Se abrirá una nueva pestaña en el navegador en el panel de eventos, en esta parte se mostrará el código de pruebas (Mantén esta pestaña abierta para los pasos siguientes):

13. Regresar al paso 12 y solo finalizar el proceso.

Instalación e implementación de la API de conversiones de Facebook en Laravel

Instalar el Facebook Business SDK para PHP

composer require facebook/php-business-sdk

Agregar las siguientes variables de entorno al archivo .env de Laravel

...
FACEBOOK_PIXEL_ID="1234567890"
FACEBOOK_CONVERSIONS_API_ACCESS_TOKEN="EAAmCSR9..."
FACEBOOK_CONVERSIONS_TEST_CODE="TEST85..."

Crear una clase que maneje toda la lógica de la API de conversiones:

<?php

namespace App\Services;

use FacebookAds\Api;
use FacebookAds\Logger\CurlLogger;
use FacebookAds\Object\ServerSide\ActionSource;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequest;
use FacebookAds\Object\ServerSide\UserData;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class FacebookConversionsApiService
{

    const PAGE_VIEW = 'PageView';
    const VIEW_CONTENT = 'ViewContent';
    const LEAD = 'Lead';

    protected $access_token;
    protected $pixel_id;
    protected $request;
    protected $event_name;
    protected $event_id;

    public function __construct(Request $request, $access_token = null, $pixel_id = null)
    {
        $this->request = $request;
        $this->access_token = $access_token ?: env('FACEBOOK_CONVERSIONS_API_ACCESS_TOKEN');
        $this->pixel_id = $pixel_id ?: env('FACEBOOK_PIXEL_ID');
    }

    public function emit($event_name = 'PageView', $page_name = null, $event_id = null, $use_referer_as_url = false)
    {
        if (!$this->access_token) {
            return;
        }

        try {
            $api = Api::init(null, null, $this->access_token);
            $api->setLogger(new CurlLogger());
            $client_info = $this->getClientInfo();
            $url = $use_referer_as_url ? $this->request->headers->get('referer') : $this->request->url();
            $eventId = $event_id ? : time();

            $this->event_name = $event_name;
            $this->event_id = $eventId;

            $user_data = (new UserData())
                ->setClientUserAgent($client_info['user_agent'])
                ->setClientIpAddress($client_info['ip_address']);

            $custom_data = (new CustomData())
                ->setContentName($page_name);

            $event = (new Event())
                ->setEventName($event_name)
                ->setEventId($eventId)
                ->setEventTime(time())
                ->setEventSourceUrl($url)
                ->setUserData($user_data)
                ->setCustomData($custom_data)
                ->setActionSource(ActionSource::WEBSITE);

            $events = [$event];

            $request = (new EventRequest($this->pixel_id))
                ->setEvents($events)
                ->setTestEventCode(env('FACEBOOK_CONVERSIONS_TEST_CODE'));

            if (!env('FACEBOOK_CONVERSIONS_TEST_CODE')) {
                $request->execute();
            } else {
                $response = $request->execute();
                Log::debug('FACEBOOK_CONVERSIONS_API_RESPONSE', ['response' => print_r($response, true)]);
            }
        } catch (\Exception $error) {

            Log::error('FACEBOOK_CONVERSIONS_API', ['response' => print_r($error->getMessage(), true)]);
        }
    }

    public function getDeduplicationData()
    {
        return [
            'event_name' => $this->event_name,
            'event_id' => $this->event_id,
        ];
    }

    private function getClientInfo()
    {
        $user_agent = $this->getClientUserAgent();
        $ip_address = $this->getClientIPAddress();

        return [
            'user_agent' => $user_agent,
            'ip_address' => $ip_address,
        ];
    }

    private function getClientUserAgent()
    {
        return $this->request->server('HTTP_USER_AGENT');
    }

    private function getClientIPAddress()
    {

        if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
            $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
            $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
        }

        $client  = @$_SERVER['HTTP_CLIENT_IP'];
        $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
        $remote  = $_SERVER['REMOTE_ADDR'];

        if (filter_var($client, FILTER_VALIDATE_IP)) {
            $clientIp = $client;
        } elseif (filter_var($forward, FILTER_VALIDATE_IP)) {
            $clientIp = $forward;
        } else {
            $clientIp = $remote;
        }

        return $clientIp;
    }
}
  • En la línea 28, el constructor de la clase recibe una instancia del request que será pasado desde el controlador donde se implemente.
  • En la línea 35, la método “emit” se encarga de configura la api y de enviar el evento a facebook. Recibe como parámetros:
    • Tipo del evento,
    • Texto del evento (opcional en PageView) Ej. “Producto X Talla M
    • ID del evento (sino se envía se asigna un timestamp [time()])
  • En mi caso particular tengo tres eventos definidos como constantes que se pasan al método “emit”:
    • FacebookConversionsApiService::PAGE_VIEW
    • FacebookConversionsApiService::VIEW_CONTENT
    • FacebookConversionsApiService::LEAD
  • En la línea 85, el método “getDeduplicationData” regresa un array con el tipo e id del evento que recibió previamente el método “emit”, estos valores se deberán pasar a la vista y ser enviados por medio del pixel de Facebook con el fin de que Facebook identifique los eventos duplicados.
  • En la línea 93, el método “getClientInfo” regresa un array con el agent (navegador del usuario) y la ip del usuario.
  • En la línea 104, el método “getClientUserAgent” regresa información del navegador que está utilizando el usuario.
  • En la línea 109, el método “getClientIPAddress” tratará de regresar la verdadera ip del usuario, esto debido a que nuestro servidor puede estar detrás un balanceador de carga o un servicio de caching como CloudFlare.

Implementación de la clase anterior:

use App\Services\FacebookConversionsApiService;
 
public function index(Request $request)
{
    ...
    $page_name = "{$city} - {$month} {$day}";
    $fbcapi = new FacebookConversionsApiService($request);
    $fbcapi->emit(FacebookConversionsApiService::VIEW_CONTENT, $page_name, "evt_{$model->id}");
    $fb_pixel_data = $fbcapi->getDeduplicationData();

    ...
    return view('view_demo', [..., 'fb_pixel_data' => $fb_pixel_data]);
}

Imprimiendo los valores de deduplicación (sí, así escribe) dentro de la implementación de pixel de Facebook en el frontend, se puede disparar este evento manualmente al hacer clic, llamando a esta función que habilita el script del pixel:

fbq('track', '{{ $fb_pixel_data['event_name'] }}', {}, {eventID: '{{ $fb_pixel_data['event_id'] }}'});

O directamente en el script del pixel (línea 12):

<!-- Facebook Pixel Code -->
<script>
    !function(f,b,e,v,n,t,s)
    {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};
    if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
    n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];
    s.parentNode.insertBefore(t,s)}(window,document,'script',
    'https://connect.facebook.net/en_US/fbevents.js');
    fbq('init', '{{ env('FACEBOOK_PIXEL_ID') }}');
    fbq('track', '{{ $fb_pixel_data['event_name'] }}', {}, {eventID: '{{ $fb_pixel_data['event_id'] }}'});
</script>
<noscript>
    <img height="1" width="1"
    src="https://www.facebook.com/tr?id={{ env('FACEBOOK_PIXEL_ID') }}&ev={{ $fb_pixel_data['event_name'] }}&eid={{ $fb_pixel_data['event_id'] }}
    &noscript=1"/>
</noscript>
<!-- End Facebook Pixel Code -->

Para hacer pruebas es necesario enviar el código que generamos previamente en el paso 12, la clase que se hizo anteriormente envía este código en la línea 71, si la variable de entorno (FACEBOOK_CONVERSIONS_TEST_CODE) contiene el código entonces la petición se enviará como una prueba de lo contrario si la variable no existe o es nula entonces se enviará como una petición real.

Nota: Este código cambia cada cierto tiempo.

Para hacer una prueba solo es necesario visitar la url que corresponda con el controlador donde está la implementación que emite el evento.

Y finalmente en el panel de eventos, en la pestaña “Probar eventos” se visualizarán de la siguiente manera:

Recursos:

Repositorio en github del SDK:

https://github.com/facebook/facebook-php-business-sdk

Documentación oficial: