Retrieving Leads

There are three ways to read leads: TSV download, bulk-read, and with Webhooks.

Permissions

To read leads or get realtime updates, you need a Page admin's access token for the page with the ad's promoted object.

You can manage user rights with Page roles. In addition, if you need to allow leads download for user with non-admin role on the page, you can whitelist it with leadgen_whitelisted_users endpoint.

TSV Download

You can query list of all forms with access links for TSV download at {page_id}/leadgen_forms.

use FacebookAds\Object\Page;

$page = new Page(<PAGE_ID>);
$leadgen_forms = $page->getLeadgenForms();
from facebookads.adobjects.page import Page

page = Page(<PAGE_ID>)
leadgen_forms = page.get_leadgen_forms()
curl -G \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<PAGE_ID>/leadgen_forms

Note the field is labeled leadgen_export_csv_url although the only supported format is TSV. Or you can directly query specific lead generation form:

use FacebookAds\Object\LeadgenForm;

$form = new LeadgenForm(<FORM_ID>);
$form->read();
from facebookads.adobjects.leadgenform import LeadgenForm

form = LeadgenForm(<LEADGEN_FORM_ID>)
form.remote_read()
curl -G \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<FORM_ID>

Response:

{
  "id": "<LEAD_GEN_FORM_ID>",
  "leadgen_export_csv_url": "https://www.facebook.com/ads/lead_gen/export_csv?type=form&amp;id=<FORM_ID>",
  "locale": "en_US",
  "name": "My Form",
  "status": "ACTIVE"
}

Filtering

Optionally you can filter the URL response to download leads for a specified date range. Use from_date and to_date in a POSIX or UNIX time format, expressing the number of seconds since epoch. For example, to download leads for the time period starting 2016-01-13 18:20:31 UTC and ending 2016-01-14 18:20:31 UTC:

https://www.facebook.com/ads/lead_gen/export_csv/?id=<FORM_ID>&amp;type=form&amp;from_date=1482698431&amp;to_date=1482784831

Note:

  • If from_date not set, or is a value less than the form creation time, the form creation time is used.
  • If to_date not set, or is a timestamp greater than the present time, current time is used.

If any entries lack Ad IDs or Adgroup IDs in the TSV, it may be due to the following reasons:

  • The lead is generated from organic reach. is_organic in the TSV displays 1 in this case. Otherwise the value is 0.
  • The lead may be submitted from an Ad Preview.
  • Anyone downloading leads lacks Advertiser privileges on the Ad Account running the Lead ad.

Bulk Read

The leads exists on both ad group and form nodes. This returns all data associated with their respective objects. Because a form can be re-used for many ads, your form could contain far more leads than an ad using it.

To read in-bulk by ad:

use FacebookAds\Object\Ad;

$ad = new Ad(<AD_ID>);
$leads = $ad->getLeads();
from facebookads.adobjects.ad import Ad

ad = Ad(<AD_ID>)
leads = ad.get_leads()
APINodeList<Lead> leads = new Ad(<AD_ID>, context).getLeads()
  .execute();
curl -G \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<AD_ID>/leads

To read by form:

use FacebookAds\Object\LeadgenForm;

$form = new LeadgenForm(<FORM_ID>);
$leads = $form->getLeads();
from facebookads.adobjects.leadgenform import LeadgenForm

form = LeadgenForm(<LEADGEN_FORM_ID>)
leads = form.get_leads()
curl -G \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<FORM_ID>/leads

The response:

{
  "data": [
    {
      "created_time": "2018-02-28T08:49:14+0000", 
      "id": "<LEAD_ID>", 
      "ad_id": "<AD_ID>",
      "form_id": "<FORM_ID>",
      "field_data": [
        {
          "name": "car_make",
          "values": [
            "Honda"
          ]
        }, 
        {
          "name": "full_name", 
          "values": [
            "Joe Example"
          ]
        }, 
        {
          "name": "email", 
          "values": [
            "joe@example.com"
          ]
        },
      ]
    }
  ],
  "paging": {
    "cursors": {
      "before": "OTc2Nz3M8MTgyMzU1NDMy", 
      "after": "OTcxNjcyOTg8ANTI4NzE4"
    }
  }
}

Reading Custom Disclaimer Responses

The field_data does not contain the responses to optional custom disclaimer checkboxes that the user would have filled out. To retrieve the responses, you can use the custom_disclaimer_responses field.

curl \
-F "access_token=<ACCESS_TOKEN>" \
"https://graph.facebook.com/<API_VERSION>/<LEAD_ID>?fields=custom_disclaimer_responses"

Filtering Leads

This example filters leads based on timestamps. Timestamps should be Unix timestamp.

use FacebookAds\Object\Ad;
use FacebookAds\Object\Fields\AdReportRunFields;

$ad = new Ad(<AD_ID>);
$time_from = (new \DateTime("-1 week"))->getTimestamp();
$leads = $ad->getLeads(array(), array(
  AdReportRunFields::FILTERING => array(
    array(
      'field' => 'time_created',
      'operator' => 'GREATER_THAN',
      'value' => $time_from,
    ),
  ),
));
curl -G \
  --data-urlencode 'filtering=[ 
    { 
      "field": "time_created", 
      "operator": "GREATER_THAN", 
      "value": 1504798911 
    } 
  ]' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<AD_ID>/leads

Tokenization

If the form has customized field IDs, the fields and values returned will be the specified fields and values.

Webhooks

Get real time updates when leads are filled out. See Lead Ads with Webhooks, Video.

Many CRMs provide real time updates to migrate Lead ads data into the CRMs. See Available CRM Integration.

Setup

1. Set up endpoint to handle realtime pings

The ping for real time updates is structured as follows. Read more at Real Time Updates, Blog.

Multiple changes can come in through the ping in the changes array.

array(
  "object" => "page",
  "entry" => array(
    "0" => array(
      "id" => 153125381133,
      "time" => 1438292065,
      "changes" => array(
        "0" => array(
          "field" => "leadgen",
          "value" => array(
            "leadgen_id" => 123123123123,
            "page_id" => 123123123,
            "form_id" => 12312312312,
            "adgroup_id" => 12312312312,
            "ad_id" => 12312312312,
            "created_time" => 1440120384
          )
        ),
        "1" => array(
          "field" => "leadgen",
          "value" => array(
            "leadgen_id" => 123123123124,
            "page_id" => 123123123,
            "form_id" => 12312312312,
            "adgroup_id" => 12312312312,
            "ad_id" => 12312312312,
            "created_time" => 1440120384
          )
        )
      )
    )
  )
)

You can use leadgen_id to retrieve data associated with the lead:

use FacebookAds\Object\Lead;

$form = new Lead(<LEAD_ID>);
$form->read();
from facebookads.adobjects.lead import Lead

lead = Lead(<LEAD_ID>)
lead.remote_read()
curl -G \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<LEAD_ID>

The response:

{
  "created_time": "2015-02-28T08:49:14+0000", 
  "id": "<LEAD_ID>", 
  "ad_id": "<AD_ID>",
  "form_id": "<FORM_ID>",
  "field_data": [{
    "name": "car_make",
    "values": [
      "Honda"
    ]
  }, 
  {
    "name": "full_name", 
    "values": [
      "Joe Example"
    ]
  }, 
  {
    "name": "email", 
    "values": [
      "joe@example.com"
    ]
  }]
}

2. Subscribe app to leadgen events

To subcribe to leadgen event, your server should respond with HTTP GET requests as described in Receiving API Updates in Real Time with Webhooks.

After your callback URL is set up, subscribe to the leadgen webhook in your Apps's Dashboard or through an API call:

To subscribe through the API you need an app access token, not a user access token:

curl \
-F "object=page" \
-F "callback_url=https://www.yourcallbackurl.com" \
-F "fields=leadgen" \
-F "verify_token=abc123" \
-F "access_token=<APP_ACCESS_TOKEN>" \
"https://graph.facebook.com/<API_VERSION>/<APP_ID>/subscriptions"

3. Get page token

Generate a single, long-lived page token to continuously fetch data without worrying about it expiration:

  1. Get a regular user token.
  2. Convert it into a long-lived token
  3. with the long lived user's access token, request the page token:
use FacebookAds\Api;

$accounts = Api::instance()->call('/me/accounts');
from facebookads import FacebookAdsApi

accounts = FacebookAdsApi.get_default_api().call('GET', ('/me/accounts',))
new User("me", context).getAccounts()
  .execute();
curl -G \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/me/accounts

The response:

{
  "data": [
    {
      "access_token": "[REDACTED]",
      "category": "Pet",
      "name": "Puppy",
      "id": "153125381133",
      "perms": [
        "ADMINISTER",
        "EDIT_PROFILE",
        "CREATE_CONTENT",
        "MODERATE_CONTENT",
        "CREATE_ADS",
        "BASIC_ADMIN"
      ]
    },
  ]
}

This long-lived page token has no expiration date and you can hard-code it in simple RTU integrations to get leads data.

4. Subscribe the page to the app

With the access_token for the page you need to subscribe, make the call below to authenticate an app for your page. You need to have at least MODERATE_CONTENT permission to the page in order to perform this action.

use FacebookAds\Api;
use FacebookAds\Http\RequestInterface;

Api::instance()->call(
  '/' . <PAGE_ID> . '/subscribed_apps',
  RequestInterface::METHOD_POST);
curl \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/<PAGE_ID>/subscribed_apps

The Facebook app associated with your token is authenticated for page updates; you do not need to specify app ID.

On success, real time pings occur on events with a delay of up to a few minutes. See Troubleshooting Real-time Integrations.