Billing Events

billing_event defines events you want to pay for such as impressions, clicks, or various actions. Billing depends on the size of your audience and your budget.

You can choose between a daily or a lifetime budget, as well as a cost per thousand impressions bid (CPM) or cost per click bid (CPC). Facebook uses maximum bids for billing; this means if you bid $5 cost per click (CPC), you'll be charged no more than $5. In most cases, you'll be charged less.

For example, to optimize for POST_ENGAGEMENT and pay per IMPRESSIONS:

curl -X POST \ -F 'name="My First Adset"' \ -F 'lifetime_budget=20000' \ -F 'start_time="2024-04-25T03:51:50-0700"' \ -F 'end_time="2024-05-05T03:51:50-0700"' \ -F 'campaign_id="<AD_CAMPAIGN_ID>"' \ -F 'bid_amount=500' \ -F 'billing_event="IMPRESSIONS"' \ -F 'optimization_goal="POST_ENGAGEMENT"' \ -F 'targeting={ "facebook_positions": [ "feed" ], "geo_locations": { "countries": [ "US" ], "regions": [ { "key": "4081" } ], "cities": [ { "key": 777934, "radius": 10, "distance_unit": "mile" } ] }, "genders": [ 1 ], "age_max": 24, "age_min": 20, "behaviors": [ { "id": 6002714895372, "name": "All travelers" } ], "life_events": [ { "id": 6002714398172, "name": "Newlywed (1 year)" } ], "publisher_platforms": [ "facebook" ], "device_platforms": [ "desktop" ] }' \ -F 'status="PAUSED"' \ -F 'access_token=<ACCESS_TOKEN>' \ https://graph.facebook.com/v19.0/act_<AD_ACCOUNT_ID>/adsets
'use strict'; const bizSdk = require('facebook-nodejs-business-sdk'); const AdAccount = bizSdk.AdAccount; const AdSet = bizSdk.AdSet; 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 First Adset', 'lifetime_budget' : '20000', 'start_time' : '2024-04-01T11:26:40-0700', 'end_time' : '2024-04-11T11:26:40-0700', 'campaign_id' : '<adCampaignLinkClicksID>', 'bid_amount' : '500', 'billing_event' : 'IMPRESSIONS', 'optimization_goal' : 'POST_ENGAGEMENT', 'targeting' : {'facebook_positions':['feed'],'geo_locations':{'countries':['US'],'regions':[{'key':'4081'}],'cities':[{'key':777934,'radius':10,'distance_unit':'mile'}]},'genders':[1],'age_max':24,'age_min':20,'behaviors':[{'id':6002714895372,'name':'All travelers'}],'life_events':[{'id':6002714398172,'name':'Newlywed (1 year)'}],'publisher_platforms':['facebook'],'device_platforms':['desktop']}, 'status' : 'PAUSED', }; const adsets = (new AdAccount(id)).createAdSet( fields, params ); logApiCallResult('adsets api call complete.', adsets);
require __DIR__ . '/vendor/autoload.php'; use FacebookAds\Object\AdAccount; use FacebookAds\Object\AdSet; 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 First Adset', 'lifetime_budget' => '20000', 'start_time' => '2024-04-01T11:26:40-0700', 'end_time' => '2024-04-11T11:26:40-0700', 'campaign_id' => '<adCampaignLinkClicksID>', 'bid_amount' => '500', 'billing_event' => 'IMPRESSIONS', 'optimization_goal' => 'POST_ENGAGEMENT', 'targeting' => array('facebook_positions' => array('feed'),'geo_locations' => array('countries' => array('US'),'regions' => array(array('key' => '4081')),'cities' => array(array('key' => 777934,'radius' => 10,'distance_unit' => 'mile'))),'genders' => array(1),'age_max' => 24,'age_min' => 20,'behaviors' => array(array('id' => 6002714895372,'name' => 'All travelers')),'life_events' => array(array('id' => 6002714398172,'name' => 'Newlywed (1 year)')),'publisher_platforms' => array('facebook'),'device_platforms' => array('desktop')), 'status' => 'PAUSED', ); echo json_encode((new AdAccount($id))->createAdSet( $fields, $params )->exportAllData(), JSON_PRETTY_PRINT);
from facebook_business.adobjects.adaccount import AdAccount from facebook_business.adobjects.adset import AdSet 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 First Adset', 'lifetime_budget': '20000', 'start_time': '2024-04-01T11:26:40-0700', 'end_time': '2024-04-11T11:26:40-0700', 'campaign_id': '<adCampaignLinkClicksID>', 'bid_amount': '500', 'billing_event': 'IMPRESSIONS', 'optimization_goal': 'POST_ENGAGEMENT', 'targeting': {'facebook_positions':['feed'],'geo_locations':{'countries':['US'],'regions':[{'key':'4081'}],'cities':[{'key':777934,'radius':10,'distance_unit':'mile'}]},'genders':[1],'age_max':24,'age_min':20,'behaviors':[{'id':6002714895372,'name':'All travelers'}],'life_events':[{'id':6002714398172,'name':'Newlywed (1 year)'}],'publisher_platforms':['facebook'],'device_platforms':['desktop']}, 'status': 'PAUSED', } print AdAccount(id).create_ad_set( 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).createAdSet() .setName(\"My First Adset\") .setLifetimeBudget(20000L) .setStartTime(\"2024-04-01T11:26:40-0700\") .setEndTime(\"2024-04-11T11:26:40-0700\") .setCampaignId(\"<adCampaignLinkClicksID>\") .setBidAmount(500L) .setBillingEvent(AdSet.EnumBillingEvent.VALUE_IMPRESSIONS) .setOptimizationGoal(AdSet.EnumOptimizationGoal.VALUE_POST_ENGAGEMENT) .setTargeting( new Targeting() .setFieldAgeMax(24L) .setFieldAgeMin(20L) .setFieldBehaviors(Arrays.asList( new IDName() .setFieldId(6002714895372L) .setFieldName(\"All travelers\") )) .setFieldDevicePlatforms(Arrays.asList(Targeting.EnumDevicePlatforms.VALUE_DESKTOP)) .setFieldFacebookPositions(Arrays.asList(\"feed\")) .setFieldGenders(Arrays.asList(1L)) .setFieldGeoLocations( new TargetingGeoLocation() .setFieldCities(Arrays.asList( new TargetingGeoLocationCity() .setFieldDistanceUnit(\"mile\") .setFieldKey(777934L) .setFieldRadius(10L) )) .setFieldCountries(Arrays.asList(\"US\")) .setFieldRegions(Arrays.asList( new TargetingGeoLocationRegion() .setFieldKey(\"4081\") )) ) .setFieldLifeEvents(Arrays.asList( new IDName() .setFieldId(6002714398172L) .setFieldName(\"Newlywed (1 year)\") )) .setFieldPublisherPlatforms(Arrays.asList(\"facebook\")) ) .setStatus(AdSet.EnumStatus.VALUE_PAUSED) .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) adsets = ad_account.adsets.create({ name: 'My First Adset', lifetime_budget: '20000', start_time: '2024-04-01T11:26:40-0700', end_time: '2024-04-11T11:26:40-0700', campaign_id: '<adCampaignLinkClicksID>', bid_amount: '500', billing_event: 'IMPRESSIONS', optimization_goal: 'POST_ENGAGEMENT', targeting: {'facebook_positions':['feed'],'geo_locations':{'countries':['US'],'regions':[{'key':'4081'}],'cities':[{'key':777934,'radius':10,'distance_unit':'mile'}]},'genders':[1],'age_max':24,'age_min':20,'behaviors':[{'id':6002714895372,'name':'All travelers'}],'life_events':[{'id':6002714398172,'name':'Newlywed (1 year)'}],'publisher_platforms':['facebook'],'device_platforms':['desktop']}, status: 'PAUSED', })

Once you select optimization_goal, you may have one or more billing_event options. See Optimization Goal and Billing Events and CPA.

For example, imagine you have a campaign with optimization_goal of APP_INSTALLS and bid_amount as $10.00. You can choose IMPRESSIONS or APP_INSTALLS as billing_event. If Facebook could perfectly estimate the chance someone installs your app 100%, either choice gives you the same number of impressions, the same number of installs, and the same total budget spent.

With 1% chance of install per view and 1,000 views, you would get 10 installs for $100.00 or less. If billing_event is IMPRESSIONS, each impression costs is about $0.10, which is bid_amount times probability of optimization_goal. If billing_event is APP_INSTALLS, each installation costs $10.00 or less.

In reality, results from two different billing_events vary due to budget pacing and variance between actual actions and our predictions.

IMPRESSIONS example

Imagine a Mobile App Install ad with these settings:

  • optimization_goal: APP_INSTALLS
  • optimization_goal probability from Facebook: 1%
  • bid_amount: $10.00
  • billing_event: IMPRESSIONS
  • Each impression cost: $0.10, or bid_amount
  • optimization_goal probability, or less
  • budget: not a direct factor

After 1,000 Accounts Center accounts see your ad and you spend $100.00, it's possible only .5%, or 5 Accounts Center accounts install your app. So your actual cost per installation (CPI) is $20.00 or less; more than your bid_amount at $10.00. However, while CPI here exceeds bid_amount, it's unlikely to happen after you run a campaign a while and you see a reasonable amount of installs. This improves Facebook predictive models, ads delivery, and your costs and results. Generally, CPI may be slightly higher than bid_amount for campaigns with very short durations or with very few actions taken.

APP_INSTALLS Example

Here is an example of a Mobile App Install ad, which demonstrates a principle you should understand about any ads experiencing sparse events. This campaign has these settings:

  • optimization_goal: APP_INSTALLS
  • optimization_goal from Facebook: 1%
  • bid_amount: $10.00
  • billing_event: APP_INSTALLS
  • Each install cost: $10.00 (bid_amount) or less
  • daily_budget: $100.00

Facebook's ad pacing tries to evenly deliver ads and spend your budget over time. If you get 10 app installs in the morning, your daily budget is spent. Your ad gets no more delivery and you have very uneven delivery. Alternately, if your ad gets 3 installs quickly, but then few Accounts Center accounts install it later, our systems increases your effective bid to spend your budget. But day's end, your ad only gets 5 installs and it's also under-delivered.

In these examples your cost per install is $10.00 or less, but you miss smooth ads delivery. Because app install events are relatively sparse, it is hard to pace evenly. Other sparse events include PAGE_LIKES and OFFER_CLAIMS.

IMPRESSIONS as billing_event

When to use

Use IMPRESSIONS when you have a budget-constrained campaign, and you want to have the campaign delivered smoothly, with all budget spent by the end time. In this case, our pacing system quickly adjusts to impression-based billing.

When to avoid

To be certain CPI is less than or equal to bid_amount, do not use IMPRESSIONS as billing_event. This has some variance based on actual actions taken. Use APP_INSTALLS.

APP_INSTALL or other actions as billing_event

When to use

Use APP_INSTALL or other actions as billing_event for bid-constrained campaigns. This means your budget is high enough to avoid pacing issues and your priority is cost per action no higher than bid_amount. In these cases, your average cost per action is less than or equal to bid_amount.

When to avoid

If your ad set has limited budget and you need smooth delivery. This means we adjust effective bid over time so it generates as many optimization_goals possible for your budget. See Ad Delivery and Pacing.

For frequent events such as POST_ENGAGEMENT and LINK_CLICKS, uneven pacing and infrequent billing_events are unlikely. If you set billing_event to a frequent event, Facebook can keep your cost per action close to bid_amount or lower, while having smooth delivery.

Validation

Buying Type and Billing Events

buying_type is the way in which the advertiser pays for their delivery, defined on the campaign level. Most of the time we just use AUCTION, but there are a few special cases where we either bill based off of prediction, known as RESERVED, or use a fixed price means of negotiating the price an advertiser will pay, known as FIXED_CPM. Campaigns with buying_type require ad sets with a billing_event defined.

Valid billing_events for each buying_type:

AUCTION RESERVED FIXED_CPM

IMPRESSIONS

LINK_CLICKS

APP_INSTALLS

PAGE_LIKES

POST_ENGAGEMENT

VIDEO_VIEWS

Optimization Goal and Billing Events

Starting on v9, CPA billing for app ads is deprecated, you cannot set both billing event and optimization goal to APP_INSTALLS. Instead, we recommend using the impression billing events. You can still specify APP_INSTALLS under billing_event or optimization_goal, but not both at the same time.

For buying_type=AUCTION campaigns, with an optimization_goal set, we have restrictions on what billing_event you can choose for your ad set.

In the restrictions below, we assume you have an objective specified on the campaign level.

`optimization_goal` Valid ad set `billing_event`

APP_INSTALLS

IMPRESSIONS

AD_RECALL_LIFT

IMPRESSIONS

ENGAGED_USERS

IMPRESSIONS

EVENT_RESPONSES

IMPRESSIONS

IMPRESSIONS

IMPRESSIONS

LEAD_GENERATION

IMPRESSIONS

LINK_CLICKS

LINK_CLICKS, IMPRESSIONS

OFFSITE_CONVERSIONS

IMPRESSIONS

PAGE_LIKES

IMPRESSIONS

POST_ENGAGEMENT

IMPRESSIONS. As of v2.11 POST_ENGAGEMENT not an option.

REACH

IMPRESSIONS

REPLIES

IMPRESSIONS

SOCIAL_IMPRESSIONS

IMPRESSIONS

THRUPLAY

IMPRESSIONS, THRUPLAY

TWO_SECOND_CONTINUOUS_VIDEO_VIEWS

IMPRESSIONS, TWO_SECOND_CONTINUOUS_VIDEO_VIEWS

IMPRESSIONS and VIDEO_VIEWS

VALUE

IMPRESSIONS

LANDING_PAGE_VIEWS

IMPRESSIONS