Customer File Custom Audiences

The Marketing API allows you to build target Custom Audiences from customer information. This includes email addresses, phone numbers, names, dates of birth, gender, locations, App User IDs, Page Scoped User IDs, Apple's Advertising Identifier (IDFA), or Android Advertising ID.

As the owner of your business's data, you are responsible for creating and managing this data. This includes information from your Customer Relationship Management (CRM) systems. To create audiences, you must share your data in a hashed format to maintain privacy. See Hashing and Normalizing Data. Facebook compares this with our hashed data to see if we should add someone on Facebook to your ad's audience.

You can add an unlimited number of records to an audience, but only up to 10000 at a time. Changes to your Custom Audiences don't happen immediately and usually take up to 24 hours. The number of records you request to remove and/or the number of Custom Audiences your account contains will increase the amount of time it takes to process this request.

To improve how advertisers create and manage their audiences, Customer File Custom Audiences that have not been used in any active ad sets in over two years will be flagged for deletion on a rolling basis. You will need to provide us with your instructions before we take any action. Once audiences are moved to the “Expiring Audience” stage and flagged, you will need to provide your instructions by either using the flagged audience in an active ad set, which we will consider an instruction to retain the audience, or by deciding not to use the flagged audience in an active ad set, which we will consider an instruction to delete the audience. For more information, see the Custom Audiences Overview documentation.

If you share conversion events using the Conversions API, you can create a website Custom Audience without additional data uploads. However, you can continue uploading supported customer information to create a Customer File Custom Audience.

Use our new Replace API to completely remove existing users of an audience and replace them with a new set of users. An audience update made with the Replace API does not move your ad set back to the learning phase.

Build a Custom Audience

Step 1: Create an empty Custom Audience

Specify subtype=CUSTOM and customer_file_source in your API call.

curl -X POST \ -F 'name="My new Custom Audience"' \ -F 'subtype="CUSTOM"' \ -F 'description="People who purchased on my website"' \ -F 'customer_file_source="USER_PROVIDED_ONLY"' \ -F 'access_token=<ACCESS_TOKEN>' \ https://graph.facebook.com/v12.0/act_<AD_ACCOUNT_ID>/customaudiences
'use strict'; const bizSdk = require('facebook-nodejs-business-sdk'); const AdAccount = bizSdk.AdAccount; const CustomAudience = bizSdk.CustomAudience; const access_token = '<ACCESS_TOKEN>'; const app_secret = '<APP_SECRET>'; const app_id = '<APP_ID>'; const id = '<AD_ACCOUNT_ID>'; const api = bizSdk.FacebookAdsApi.init(access_token); const showDebugingInfo = true; // Setting this to true shows more debugging info. if (showDebugingInfo) { api.setDebug(true); } const logApiCallResult = (apiCallName, data) => { console.log(apiCallName); if (showDebugingInfo) { console.log('Data:' + JSON.stringify(data)); } }; let fields, params; fields = [ ]; params = { 'name' : 'My new Custom Audience', 'subtype' : 'CUSTOM', 'description' : 'People who purchased on my website', 'customer_file_source' : 'USER_PROVIDED_ONLY', }; const customaudiences = (new AdAccount(id)).createCustomAudience( fields, params ); logApiCallResult('customaudiences api call complete.', customaudiences);
require __DIR__ . '/vendor/autoload.php'; use FacebookAds\Object\AdAccount; use FacebookAds\Object\CustomAudience; use FacebookAds\Api; use FacebookAds\Logger\CurlLogger; $access_token = '<ACCESS_TOKEN>'; $app_secret = '<APP_SECRET>'; $app_id = '<APP_ID>'; $id = '<AD_ACCOUNT_ID>'; $api = Api::init($app_id, $app_secret, $access_token); $api->setLogger(new CurlLogger()); $fields = array( ); $params = array( 'name' => 'My new Custom Audience', 'subtype' => 'CUSTOM', 'description' => 'People who purchased on my website', 'customer_file_source' => 'USER_PROVIDED_ONLY', ); echo json_encode((new AdAccount($id))->createCustomAudience( $fields, $params )->exportAllData(), JSON_PRETTY_PRINT);
from facebook_business.adobjects.adaccount import AdAccount from facebook_business.adobjects.customaudience import CustomAudience from facebook_business.api import FacebookAdsApi access_token = '<ACCESS_TOKEN>' app_secret = '<APP_SECRET>' app_id = '<APP_ID>' id = '<AD_ACCOUNT_ID>' FacebookAdsApi.init(access_token=access_token) fields = [ ] params = { 'name': 'My new Custom Audience', 'subtype': 'CUSTOM', 'description': 'People who purchased on my website', 'customer_file_source': 'USER_PROVIDED_ONLY', } print AdAccount(id).create_custom_audience( fields=fields, params=params, )
import com.facebook.ads.sdk.*; import java.io.File; import java.util.Arrays; public class SAMPLE_CODE_EXAMPLE { public static void main (String args[]) throws APIException { String access_token = \"<ACCESS_TOKEN>\"; String app_secret = \"<APP_SECRET>\"; String app_id = \"<APP_ID>\"; String id = \"<AD_ACCOUNT_ID>\"; APIContext context = new APIContext(access_token).enableDebug(true); new AdAccount(id, context).createCustomAudience() .setName(\"My new Custom Audience\") .setSubtype(CustomAudience.EnumSubtype.VALUE_CUSTOM) .setDescription(\"People who purchased on my website\") .setCustomerFileSource(CustomAudience.EnumCustomerFileSource.VALUE_USER_PROVIDED_ONLY) .execute(); } }
require 'facebook_ads' access_token = '<ACCESS_TOKEN>' app_secret = '<APP_SECRET>' app_id = '<APP_ID>' id = '<AD_ACCOUNT_ID>' FacebookAds.configure do |config| config.access_token = access_token config.app_secret = app_secret end ad_account = FacebookAds::AdAccount.get(id) customaudiences = ad_account.customaudiences.create({ name: 'My new Custom Audience', subtype: 'CUSTOM', description: 'People who purchased on my website', customer_file_source: 'USER_PROVIDED_ONLY', })

Parameters

NameDescription

customer_file_source
enum string

Describes how the customer information in your Custom Audience was originally collected.
Values:

  • USER_PROVIDED_ONLY
    Advertisers collected information directly from customers
  • PARTNER_PROVIDED_ONLY
    Advertisers sourced information directly from partners (e.g., agencies or data providers)
  • BOTH_USER_AND_PARTNER_PROVIDED
    Advertisers collected information directly from customers and it was also sourced from partners (e.g., agencies)

name
string

Custom Audience name

description
string

Custom Audience description

subtype
string

Type of Custom Audience

Step 2: Specify a list of users

Use a POST API call to the /{audience_id}/users endpoint to specify the list of users you want to add to your Custom Audience.

Parameters

NameDescription

session
JSON Object

Required
Use the session parameter to track if a specific batch of users has been uploaded
If you have an upload with more than 10000 users, you need to split it into separate batches — each request can take up to 10000 users.


Example

{
  "session_id":9778993, 
  "batch_seq":10, 
  "last_batch_flag":true, 
  "estimated_num_total":99996 
} 

payload
JSON Object

Required
Includes two fields:

  • schema
  • data

Example

{ 
  "schema":"EMAIL", 
  "data":
    [
      "<HASHED_DATA>", 
      "<HASHED_DATA>", 
      "<HASHED_DATA>" 
    ]
}

The session fields

NameDescription

session_id
positive 64-bit integer

Required
Identifier used to track the session
This number must be

  • generated by the advertiser, and
  • unique within a specific ad account.

batch_seq
positive integer

Required
A number to identify the request listed in the current session This number must be

  • sequential, and
  • start from 1.

last_batch_flag
boolean

Required
If set to true, the current request is the last one from the current session. You must mark the last request to let Facebook know this is the last batch.

estimated_num_total
integer

Optional
Estimated total number of users to be uploaded in this session
This is used to improve this session's processing.

Response

A successful response includes a JSON object with the following fields:

NameDescription

audience_id
numeric string

Audience identifier

session_id
integer

The session ID you passed in

num_received
integer

Total number of users received in this session so far

num_invalid_entries
integer

The number of entries sent with incorrect hashing
Those entries did not return a match and are not added to the custom audience. This is not an exact number, but it represents the number range of users that did not match.

invalid_entry_samples
JSON Array of String or Map {string: string}

Up to 100 samples of invalid entries found in the current request

Learn more about sharing your Custom Audience with business objects.

Remove Audience Members

Use a DELETE API call to the /{audience_id}/users endpoint to specify the list of users you want to remove from your Custom Audience.

curl -X DELETE \
  --data-urlencode 'payload={ 
    "schema": "EMAIL", 
    "data": [ 
      "<HASHED_DATA>", 
      "<HASHED_DATA>", 
      "<HASHED_DATA>" 
    ] 
  }' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<VERSION>/<CUSTOM_AUDIENCE_ID>/users

Or you can add a parameter called method and set it to DELETE in the POST request used to add audience members.

You can remove people from a list with EXTERN_ID, if available.

curl -X DELETE \
  --data-urlencode 'payload={ 
    "schema": "EXTERN_ID", 
    "data": [ 
      "<ID>", 
      "<ID>", 
      "<ID>" 
    ] 
  }' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<VERSION>/<CUSTOM_AUDIENCE_ID>/users

You can remove a list of people from all Custom Audiences across your ad account using this endpoint.

There may be some reasons why this information is not processed. For example, if the ad account is not owned by a business account, you have not yet accepted the Custom Audience Terms, or the information does not match with a user.

To remove a person, include the same fields as in user update and make a HTTP DELETE call to:

https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/usersofanyaudience

Multi-Key Matching

To increase the match rate for your records, provide multiple keys in an array of individual keys, for example [EXTERN_ID, LN, FN, EMAIL]. While you do not need to hash EXTERN_ID, you must hash all personally identifying information, such as emails and names. For details see Hashing and Normalizing Data.

You can provide some or all multi-keys for a record. For details, see multi-key extern id matching.

Add users with multi-key matches

curl \
  -F 'payload={ 
    "schema": [ 
      "FN", 
      "LN", 
      "EMAIL" 
    ], 
    "data": [ 
      [ 
        "<HASH>", 
        "<HASH>", 
        "<HASH>" 
      ], 
      [ 
        "<HASH>", 
        "<HASH>", 
        "<HASH>" 
      ] 
    ] 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<VERSION>/<CUSTOM_AUDIENCE_ID>/users

Using PAGEUID

If you use the PAGEUID key, you must also include a list of Page IDs. You can only send us one PAGEUID, which should be an array with one element.

curl -X POST \
  -F 'payload={
       "schema": [
         "PAGEUID"
       ],
       "is_raw": "true",
       "page_ids": [
            "<PAGE_IDs>"
            ],
       "data": [
         [
           "<HASH>",
           "<ID>",
           "<ID>",
           "<VALUE>"
         ],
         [
           "<HASH>",
           "<ID>",
           "<ID>",
           "<VALUE>"
         ],
         [
           "<HASH>",
           "<ID>",
           "<ID>",
           "<VALUE>"
         ]
       ]
     }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<VERSION>/<CUSTOM_AUDIENCE_ID>/users

Hashing and Normalization for Multi-Key

You must hash data as SHA256; we don't support other hashing mechanisms. This is required for all data except External Identifiers, App User IDs, Page Scoped User IDs and Mobile Advertiser IDs.

Before you hash your data, normalize it so we can handle it. Only First name (FN) and Last Name (LN) support special characters and non-Roman alphabets. For the best match results, provide the Roman alphabet translation with no special characters.

KeyGuidelines

EMAIL
criteria: email addresses

Hashing required
Trim leading and trailing white space, and convert all characters to lowercase.

PHONE
criteria: phone numbers

Hashing required
Remove symbols, letters, and any leading zeroes. You should prefix the country code if the COUNTRY field is not specified.

GEN
criteria: gender

Hashing required
Use these values: m for male, f for female.

DOBY
criteria: birth year

Hashing required
Use the YYYY format: 1900 to the current year.

DOBM
criteria: birth month

Hashing required
Use the MM format: 01 to 12.

DOBD
criteria: birthday

Hashing required
Use the DD format: 01 to 31.

LN and FN
criteria: last and first names

Hashing required
Use a-z only. Lowercase only, no punctuation. Special characters in UTF-8 format.

FI
criteria: first name initial

Hashing required
Use a-z only. Lowercase only. Special characters in UTF-8 format.

ST
criteria: US states

Hashing required
Use the 2-character ANSI abbreviation code, lowercase. Normalize states outside the US in lowercase, with no punctuation, no special characters, and no white space.

CT
criteria: city

Hashing required
Use a-z only. Lowercase only, with no punctuation, no special characters, and no white space.

ZIP
criteria: zip code

Hashing required
Use lowercase, and no white space. For the US, use only the first 5 digits. For the UK, use the Area/District/Sector format.

COUNTRY
criteria: country code

Hashing required

Use lowercase, 2-letter country codes in ISO 3166-1 alpha-2.

MADID
criteria: mobile advertiser ID

Hashing NOT required Use all lowercase, and keep hyphens.

Hashing

Provide SHA256 values for normalized keys and HEX representations of this value, using lowercase for A through F. The hash function in PHP converts normalized emails and phone numbers.

ExampleResult

hash("sha256", "mary@example.com")

f1904cf1a9d73a55fa5de0ac823c4403ded71afd4c3248d00bdcd0866552bb79

hash("sha256", "15559876543")

1ef970831d7963307784fa8688e8fce101a15685d62aa765fed23f3a2c576a4e

External Identifiers

You can match people for an audience with your own identifiers, known as External Identifiers (EXTERN_ID). This can be any unique ID from the advertiser, such as loyalty membership IDs, user IDs, and external cookie IDs.

While you do not need to hash this ID, you must hash all Personally Identifying Information (PII) that you send with the EXTERN_IDs.

Read about other parameters you can pass in the Advanced matching documentation.

For better matching, you should also use the exact same format when you send the IDs. For example, if you choose to hash using SHA256, make sure to use the same hashed value.

You can use these IDs as individual keys to delete people from Custom Audiences or create new Custom Audiences. This way you don't need to re-upload any other matching keys. If you tag someone with hashed personal information and EXTERN_ID, we give EXTERN_ID lower precedence when we match them with people on Facebook.

NOTE: The data retention period for EXTERN_ID is 90 days.

You can reuse the EXTERN_ID mapping across audiences within a single ad account.

If you have an audience of EXTERN_ID fields in your ad account, create a new audience with just these identifiers.

curl \
  -F 'payload={"schema":"EXTERN_ID","data":["<ID>","<ID>"]}' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<VERSION>/<CUSTOM_AUDIENCE_ID>/users

You can also add people tagged EXTERN_ID and with multi-key matching.

curl \
  -F 'payload={ 
    "schema": [ 
      "EXTERN_ID", 
      "FN", 
      "EMAIL", 
      "LN" 
    ], 
    "data": [ 
      [ 
        "<ID>", 
        "<HASH>", 
        "<HASH>", 
        "<HASH>" 
      ], 
      [ 
        "<ID>", 
        "<HASH>", 
        "<HASH>", 
        "<HASH>" 
      ], 
      [ 
        "<ID>", 
        "<HASH>", 
        "<HASH>", 
        "<HASH>" 
      ] 
    ] 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<VERSION>/<CUSTOM_AUDIENCE_ID>/users

Facebook supports EXTERN_ID parameters for individual Ad Accounts. Facebook cannot use values from one Ad Account for any other Ad Accounts, even if the accounts belong to the same entity.

Replace Users API

The /<CUSTOM_AUDIENCE_ID>/usersreplace endpoint allows you to perform two actions with one API call: completely remove existing users from a specific audience and replace those users with a new set of users.

Using the /<CUSTOM_AUDIENCE_ID>/usersreplace endpoint allows you to automatically delete all existing users rather than having to upload a list of users you wish to delete. This endpoint does not reset your ad set's learning phase when an audience is part of active ad sets unlike POST or DELETE API calls to the /<CUSTOM_AUDIENCE_ID>/users endpoint.

The Replace Users API only works with audiences that meet the following requirements:

  • The number of users in place before running a replace process must be smaller than 100 million. If your audience is larger than 100 million, we suggest leveraging the /<CUSTOM_AUDIENCE_ID>/users endpoint to add and remove users.
  • Subtype must be set to CUSTOM.
  • You cannot replace a value-based customer file custom audience with a non-value based customer file custom audience, or vice-versa.

Get Started

Before you start a replace process, make sure your audience’s operation_status is ready or available. You cannot perform a replace operation if there is one already being executed. Additionally, we recommend not adding or removing users via /<CUSTOM_AUDIENCE_ID>/users during an ongoing replace operation via /<CUSTOM_AUDIENCE_ID>/usersreplace. If you try performing a second replace operation before the first is completed, you will receive a message indicating a replace operation is already in progress.

The maximum duration window for 1 replace session is 90 minutes. The API will reject any batches for a session received after 90 minutes from the time the session started. If you need to send batches for a duration longer than 90 minutes, we recommend waiting until the replace operation for that session is done, then using the /<CUSTOM_AUDIENCE>/users endpoint’s add operation for the rest of your uploads.

Once your audience is ready, specify the list of users you want to replace with your custom audience using a POST call to /<CUSTOM_AUDIENCE_ID>/usersreplace. Once you start the replacement progress, your audience’s operation_status switches to replace_in_progress. If your replacement operation is incomplete, your audience’s operation_status switches to replace_error.

Call Parameters

You can include the following parameters in your POST call to /<CUSTOM_AUDIENCE_ID>/usersreplace:

NameDescription

session

type: JSON object

Required.

Used to track if a specific batch of users has been uploaded. Must include a session ID and batch information. See Session Fields.


You can add up to 10000 people to an audience at a given time. If you have more than 10000 people, split your session into multiple batches, which should all have 1 session ID.


Example:

{
  'session_id':9778993, 
  'batch_seq':10, 
  'last_batch_flag':true, 
  'estimated_num_total':99996 
}

payload

type: JSON object

Required.

Used to provide the information you want to be uploaded to your audience. Must include schema and data —see Payload Fields for more information.


Example:

{ 
  "schema":"EMAIL", 
  "data":["<HASHED_EMAIL>", "<HASHED_EMAIL>", "<HASHED_EMAIL>" ]
}

Session Fields

NameDescription

session_id

type: 64-bit integer

Required.

Used to track the session. You must generate this identifier and the number must be unique within the same ad account.

batch_seq

type: integer

Required. Must start at 1.
A new replace session starts when we receive a batch_seq of 1, so make sure not to send duplicate batches with a sequence of 1 for a given session_id.
Labelling the first batch is important; the rest of the batches of a session can be duplicates or any number except 1 because we use this parameter to identify the start of the session. All non-first batches for a session should be sent after the first batch. Consider the first batch as a trigger/pre-step for the replace operation.

last_batch_flag

type: boolean

Optional.

If you don't set a last_batch_flag, we will automatically terminate the replace session 90 minutes after we receive your first batch. Any batch received after 90 minutes will be discarded.

If set to true, it means the current batch is the last one in this session. This acts as an indicator to us that you want to end the session.

estimated_num_total

type: integer

Optional.

Estimated total number of users to be uploaded in this session. Used by our system to improve a session's processing.

Payload Fields

NameDescription

schema

type: string or JSON_Array_of_string

Required.

Specify what type of information you will be providing. It can be a single key or multi key from the following list:

  • EMAIL
  • PHONE
  • GEN
  • DOBY
  • DOBM
  • DOBD
  • LN
  • FN
  • FI
  • CT
  • ST
  • ZIP
  • COUNTRY
  • MADID
  • ["hash1", "hash2", ...]. For example: ["PHONE", "LN”, “FN”, “ZIP”, “DOBYM"]

data

type: JSON_Array

Required.

List of data corresponding to the schema.


Examples:

  • If the schema is "EMAIL", the data should be a list of email sha256 hashes.
  • If the schema is a list of hashes as in the previous example, the data should be like "phone_hash_value", "LN_FN_ZIP_DOBYM".

Once you make your POST request, you get a response with the following fields:

NameDescription

account_id

type: integer

Account identifier.

session_id

type: integer

The session ID you have previously provided.

num_received

type: integer

Total number of users received in this session so far.

num_invalid_entries

type: integer

Total number of users with invalid format or unable to be decoded. If this number is not zero, re-check your data.

invalid_entry_samples

type: JSON string Array

Up to 100 samples of invalid entries in current request. Re-check your data.

Resources

There are other types of audiences you can build and target, or share: