Skip to content

Instantly share code, notes, and snippets.

@machouz
Last active April 9, 2024 10:11
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save machouz/7c027c9031ef45c0d7a3650f70897757 to your computer and use it in GitHub Desktop.
Save machouz/7c027c9031ef45c0d7a3650f70897757 to your computer and use it in GitHub Desktop.
Receive Facebook Ad Lead With Your Own Webhook (without Zapier)

Step-by-step guide: Get your FB Lead on your Webhook

This gist was created in 2023 and is inspired from tixastronauta and eladnava tutorial.

The Facebook API changes frequently. As a result, this guide might not be accurate.

1 - Create an App

Sign up for Facebook Developer access if you haven't already, from the same account as your Facebook Ads advertising account.

Create an app and select Manage business integrations as the app purpose. If you're using Facebook Business Manager, make sure to select the right Business Manager account in the app creation form, when asked to do so.

Enable the live Mode otherwise you won't be able to access real leads but only test leads.. You will need to submit your app to Facebook for review to enable Live mode.

2 - Setting Up the Server

Here is an example in Node JS of the server you can build NodeJS Server from eladnava

But you can build the same with any language.

For this you need a GET endpoint. It need to return hub.challenge if the hub.verify_token is your custom Token

And in the same path a POST endpoint. It will get notified when a new lead come with the lead_id and the page_id. After that you will need to request the facebook Graph Api to get the lead data. For this last part you will need the token we will generate in the last part.

Note: The URL need to be in https Protocol

3 - Enabling the Lead Gen Webhook

  1. Visit the Facebook Developer Center, select your app, scroll down to Webhooks and click Set Up Callback URL.
  2. Paste in the https forwarding address
  3. In the dropdown select Page.
  4. Search for the leadgen webhook, and click Test next to it, followed by Send to My Server.
  5. Verify Token: Enter CUSTOM_WEBHOOK_VERIFY_TOKEN (you may change this string for security purposes, but also remember to modify it in server.js accordingly).
  6. Click Verify and Save.
  7. Now your server need to pass the challenge.
  8. Subscribe to the leadgen event

At this part we have a working app that get notified on new lead. We just need to link this app with our Page to get notified when our Page generate a new lead.

We also have to make our server retrieve the lead infos when he get notified. For these parts we need an access token.

4 - Generate a 3-Month Page Access Token

  1. Go to https://developers.facebook.com/tools/explorer/ and generate a custom Token for your Application.
  2. Under User or Page, select the name of your page, ensure the permissions are still there, and click Generate Access Token.
  3. Add the following custom permissions which are necessary to retrieve Facebook Ads leads:
pages_show_list
ads_management
ads_read
leads_retrieval
pages_read_engagement
pages_manage_metadata
pages_manage_ads

IMPORTANT: Facebook keep changing needed permission. In step 5 it will check missing permissions, so it may be other permission you will need to add.

  1. Accept the permission dialog once again.
  2. Copy your Access Token. And go to https://developers.facebook.com/tools/debug/accesstoken and paste your Token.
  3. Check that the Type is Page
  4. If it is not is, you will have reset to go back to step 3. Most likely there is a bug that may require from you to generate the token more than once.
  5. Scroll down and extend the token to 3 month (it is the maximum).
  6. Click Debug and ensure the expiration is set to Never.

5 - Subscribe for the leadgen webhook event for the specific page we are advertising

To subscribe to our specific page, we need to manually post a request with the custom token.

curl -i -X POST 'https://graph.facebook.com/PAGE_ID/subscribed_apps?subscribed_fields=leadgen&access_token=ACCESS_TOKEN'

Check for a {"success": true} response.

Now let's check that your app is subscribed to your Page Lead generation.

Go to https://developers.facebook.com/tools/lead-ads-testing and select your Page. You will see your webhook subscribed at the bottom of the page. Just test the creation. You are supposed to get a request to your server.

IMPORTANT: Facebook keep changing needed permission so if you see other permissions missing, add the like in step 4 and retry

6 - Add App to CRM (if it is not)

Go to https://business.facebook.com/settings/leads-accesses/ and add access to the app as a CRM to the Page.

7 - Retrieve the lead data

Now your server get the leadgen_id, you can use it to retrieve the lead infos by your ACCESS_TOKEN.

For this just make a GET request (even with your browser) to: https://graph.facebook.com/LEADGEN_ID/?access_token=ACCESS_TOKEN

@dlopez-evolmind
Copy link

Hello,

I have followed all the steps and it seems that everything is well done, when I performed any test, I get empty data and I don't understand why.
If I use Postman I can collect all the data.

Please, I need to be able to solve this.

Best regards and thanks.

@machouz
Copy link
Author

machouz commented Sep 20, 2023

Hello,

I have followed all the steps and it seems that everything is well done, when I performed any test, I get empty data and I don't understand why. If I use Postman I can collect all the data.

Please, I need to be able to solve this.

Best regards and thanks.

@dlopez-evolmind
Can you try to navigate with your browser to https://graph.facebook.com/LEADGEN_ID/?access_token=ACCESS_TOKEN ?
Can you also provide your server-side code ?

@dlopez-evolmind
Copy link

dlopez-evolmind commented Sep 20, 2023

Hello,
I have followed all the steps and it seems that everything is well done, when I performed any test, I get empty data and I don't understand why. If I use Postman I can collect all the data.
Please, I need to be able to solve this.
Best regards and thanks.

@dlopez-evolmind Can you try to navigate with your browser to https://graph.facebook.com/LEADGEN_ID/?access_token=ACCESS_TOKEN ? Can you also provide your server-side code ?

test_leadgen
test_lead

Hello,

I have tried what you tell me in Chrome and I have received the Lead correctly, I attach screenshots.

I will pass you my code:

`<?php

$BASE_WEB_DIR = '/';
$BASE_APP_DIR = realpath(dirname(FILE)).$BASE_WEB_DIR;

/////////////////////////////////////////////////////////////////////////
// Parte 1: Subscripción al webhook leadgen endpoint //
// En PHP la variables cambian los '.' puntos '_' //
/////////////////////////////////////////////////////////////////////////
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$aDatos = $_GET;

    if(!empty($aDatos)) {
        // rutaDestino default
        $rutaDestino = $BASE_APP_DIR . "facebook/log/" . date('Y/m') . ".txt";

        crearEstructuraCarpetas($rutaDestino);

        $f = fopen($rutaDestino, 'a+');
        fwrite($f, date('Y-m-d H:i:s') . "\t" . json_encode($aDatos) . "\r\n");
        fclose($f);
        
        $VERIFY_TOKEN = 'MYTOKEN';
        $verify_token = $aDatos['hub_verify_token'];
        $challenge = $aDatos['hub_challenge'];
        $mode = $aDatos['hub_mode'];
    
        if (!$verify_token || !$challenge) {
            echo 'No se encuentran los parámetros hub.verify_token y hub.challenge';
            exit();
        }
    
        if ($verify_token !== $VERIFY_TOKEN) {
            echo 'El token no coincide';
            exit();
        }

        // Hacemos un echo del callenge recibido a Facebook para terminar la verificación
        echo $challenge;
        exit();
    }
}

/////////////////////////////////////////////////////////////////////////
//                  Parte 2: Leemos los Leads en tiempo real            //
/////////////////////////////////////////////////////////////////////////

$PAGE_TOKEN = 'PAGE_TOKEN';
$APP_TOKEN = 'APP_TOKEN';
$AGRICULTURA_PAGE_ID = 'AGRICULTURA_PAGE_ID';

$GRAPH_API_VERSION = 'v17.0';
$GRAPH_API_ENDPOINT = 'https://graph.facebook.com/' . $GRAPH_API_VERSION;

// Facebook mandará peticiones POST en tiempo real
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $aDatos = json_decode(file_get_contents('php://input'), true);

    // rutaDestino default
    $rutaDestino = $BASE_APP_DIR . "facebook/log/" . date('Y/m') . ".txt";

    crearEstructuraCarpetas($rutaDestino);

    $f = fopen($rutaDestino, 'a+');
    fwrite($f, date('Y-m-d H:i:s') . "\t" . json_encode($aDatos) . "\r\n");
    fclose($f);

    foreach ($aDatos['entry'] as $page) {
        foreach ($page['changes'] as $change) {
            // Necesitamos el lead gen ID para recuperar los datos del Lead.
            $page_id = $change['value']['page_id'];
            $form_id = $change['value']['form_id'];
            $leadgen_id = $change['value']['leadgen_id'];
            console_log('Page ID '.$page_id.', Form ID '.$form_id.', Lead gen ID '.$leadgen_id);
    
            // Llamamo a la API Graph para recoger los datos
            $leadgen_uri = $GRAPH_API_ENDPOINT.'/'.$leadgen_id.'?access_token='.$APP_TOKEN;
            $response = json_decode(file_get_contents($leadgen_uri));
            $id = $response->id;
            $created_time = $response->created_time;
            $field_data = $response->field_data;
    
            console_log('Lead ID '.$id);
            console_log('Created time '.$created_time);
            foreach ($field_data as $field) {
                $question = $field->name;
                $answers = $field->values;
                console_log('Question '.$question);
                console_log('Answers '.print_r($answers, true));
            }
        }
    }
    // Enviamos una petición HTTP 200 OK para indicar que hemos recibido la actualización.
    http_response_code(200);
}

function console_log($string) {
file_put_contents('php://stdout', $string.PHP_EOL);
}

function cambiarPropietario($ruta) {
if (!EN_PRE) {
chown($ruta, 'ftpinternet');
chgrp($ruta, 'ftpinternet');
}
}

function crearEstructuraCarpetas($rutaDestino, $permisos = 0775) {

$rutaFichero = '';
$aDirs = explode('/', $rutaDestino);
// recorremos todos los elementos del array menos el último que es el fichero
for ($i = 0, $hasta = (count($aDirs) - 1); $i < $hasta; $i++) {
    if (!empty($aDirs[$i])) {
        if (!is_dir($rutaFichero . $aDirs[$i])) {
            mkdir($rutaFichero . $aDirs[$i], $permisos);
            chmod($rutaFichero . $aDirs[$i], $permisos);
            cambiarPropietario($rutaFichero . $aDirs[$i]);
        }
    }

    $rutaFichero .= $aDirs[$i] . '/';
}

cambiarPropietario($rutaDestino);

}

function printr($arr, $htmlcomentado = false) {
header('X-XSS-Protection:0');
if ($htmlcomentado)
echo '';
}`

Thanks so much for help me!!

@machouz
Copy link
Author

machouz commented Sep 20, 2023

If it is working on chrome, the problem seems to come from your code.
My level in PHP is really bad so after a quick look I will say:

  • First thing never share your real tokens (plase edit to hide them in your comment or change them a little)
  • Verify that the verify token ($VERIFY_TOKEN) in your PHP code matches the one you configured on Facebook.
  • You need to check that $_GET['hub_verify_token'] match with before, your code directly uses $_GET['hub_challenge'] in the response without checking if the token matches. It's generally advisable to perform this verification.
  • Can you try logging your response before retrieving the JSON data ?

@dlopez-evolmind
Copy link

If it is working on chrome, the problem seems to come from your code. My level in PHP is really bad so after a quick look I will say:

  • First thing never share your real tokens (plase edit to hide them in your comment or change them a little)
  • Verify that the verify token ($VERIFY_TOKEN) in your PHP code matches the one you configured on Facebook.
  • You need to check that $_GET['hub_verify_token'] match with before, your code directly uses $_GET['hub_challenge'] in the response without checking if the token matches. It's generally advisable to perform this verification.
  • Can you try logging your response before retrieving the JSON data ?

Hello,

I have already edited the data, you are right, thank you.
On the other hand, to be able to link the webhook with my domain I have been able to perform the first part that is the one you mention, validating the hub_verify_token and I receive the data correctly.
The problem comes later, with each test no matter how I collect them I do not receive anything, I can delete all the code and save logs of the $_POST, $_GET, $_REQUEST that are always empty.
There is my problem, I link everything correctly but when I receive a test either from the webhook or from https://developers.facebook.com/tools/lead-ads-testing I get empty data.

I don't think it's not so much a question of the programming language, but I think I'm leaving out a part and I don't know what it is.

Best regards.

@machouz
Copy link
Author

machouz commented Sep 21, 2023

If it is working on chrome, the problem seems to come from your code. My level in PHP is really bad so after a quick look I will say:

  • First thing never share your real tokens (plase edit to hide them in your comment or change them a little)
  • Verify that the verify token ($VERIFY_TOKEN) in your PHP code matches the one you configured on Facebook.
  • You need to check that $_GET['hub_verify_token'] match with before, your code directly uses $_GET['hub_challenge'] in the response without checking if the token matches. It's generally advisable to perform this verification.
  • Can you try logging your response before retrieving the JSON data ?

Hello,

I have already edited the data, you are right, thank you. On the other hand, to be able to link the webhook with my domain I have been able to perform the first part that is the one you mention, validating the hub_verify_token and I receive the data correctly. The problem comes later, with each test no matter how I collect them I do not receive anything, I can delete all the code and save logs of the $_POST, $_GET, $_REQUEST that are always empty. There is my problem, I link everything correctly but when I receive a test either from the webhook or from https://developers.facebook.com/tools/lead-ads-testing I get empty data.

I don't think it's not so much a question of the programming language, but I think I'm leaving out a part and I don't know what it is.

Best regards.

@codediodeio
I also think that it supposed to work in any language but I haven't really underestand your code.
I find some code that look like so can you check if this works : Facebook Webhook Handler PHP ?

@dlopez-evolmind
Copy link

If it is working on chrome, the problem seems to come from your code. My level in PHP is really bad so after a quick look I will say:

  • First thing never share your real tokens (plase edit to hide them in your comment or change them a little)
  • Verify that the verify token ($VERIFY_TOKEN) in your PHP code matches the one you configured on Facebook.
  • You need to check that $_GET['hub_verify_token'] match with before, your code directly uses $_GET['hub_challenge'] in the response without checking if the token matches. It's generally advisable to perform this verification.
  • Can you try logging your response before retrieving the JSON data ?

Hello,
I have already edited the data, you are right, thank you. On the other hand, to be able to link the webhook with my domain I have been able to perform the first part that is the one you mention, validating the hub_verify_token and I receive the data correctly. The problem comes later, with each test no matter how I collect them I do not receive anything, I can delete all the code and save logs of the $_POST, $_GET, $_REQUEST that are always empty. There is my problem, I link everything correctly but when I receive a test either from the webhook or from https://developers.facebook.com/tools/lead-ads-testing I get empty data.
I don't think it's not so much a question of the programming language, but I think I'm leaving out a part and I don't know what it is.
Best regards.

@codediodeio I also think that it supposed to work in any language but I haven't really underestand your code. I find some code that look like so can you check if this works : Facebook Webhook Handler PHP ?

Hello,

that code looks a lot like mine but it validates the sha they send.
My big problem is that I get nothing, no data. It doesn't matter if it's POST, GET, REQUEST... Nothing, I can only see the $_SERVER with the server information but nothing more... If I received some data I could modify my code but I don't receive anything, I think I'm missing some part of permissions or something from the server, because as I said with postman I can see the data.

@ramyatantrymb
Copy link

Hello, Thanks for the detailed guide.
I have one query.. How can we test lead ads when the Facebook app is in dev mode. As mentioned in the Facebook documentation, Lead Ads testing tool works only when the app is live. But app can be live only after app review and for app review we need to show the usage of leads_retrieval permission. Facebook documentation also mentions that - "Development mode app users can access leads submitted by someone with a role in that same app", but how can we test the leads?

@machouz
Copy link
Author

machouz commented Nov 10, 2023

As I remember, simple apps don't pass a review. It is only necessary to make declarations on the use of the data.

@machouz
Copy link
Author

machouz commented Apr 9, 2024

It seems that Facebook made some changes in the needed permission so please check. Especially step 6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment