Bidding and Optimization

Learn how your bids and budget work with Facebook's ad auction and delivery. This covers bidding options, placing bids for desired action, setting budget limits and tracking ads delivery. Facebook's auction functions the same way for API-created ads as they do for ads from Facebook tools. See Ads Help Center, Auction.

Starting from Wednesday, March 8th, 2017, we start enforcing a budget validation to prevent creation and editing of ads with lifetime budgets exceeding 1 million USD. Reach-Frequency assets are exempt from this limit and validation. There is no change to the daily budget limit, and it was already enforced at 1 million USD.

When a life budget for an Ad exceeds this cap, you see an error: ErrorCode::ADPRO2__CAMPAIGN_BUDGET_TOO_HIGH (1885261).

Budgets

Set daily budget or lifetime budget at the ad set level. The amount you set for bid and budget are at ad account currencies minimum denomination level, such as cents for USD. All ads delivered in that set will not exceed a spend limit:

  • To run your ads continuously, choose a per day budget
  • For a fixed duration, choose a lifetime budget.

To set a daily budget of 20 dollars:

use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdSetFields;

$adset = new AdSet(null, 'act_<AD_ACCOUNT_ID>');
$adset->setData(array(
  AdSetFields::NAME => 'My First AdSet',
  AdSetFields::DAILY_BUDGET => '2000',
  AdSetFields::START_TIME => '<START_TIME>',
  AdSetFields::CAMPAIGN_ID => <CAMPAIGN_ID>,
  AdSetFields::BID_AMOUNT => <BID_AMOUNT>,
  AdSetFields::BILLING_EVENT => '<BILLING_EVENT>',
  AdSetFields::OPTIMIZATION_GOAL => $optimization_goal,
  AdSetFields::TARGETING => <TARGETING>,
));

$adset->create(array(
  AdSet::STATUS_PARAM_NAME => AdSet::STATUS_PAUSED,
));
from facebookads.adobjects.adset import AdSet
from facebookads.adobjects.adaccount import AdAccount

ad_account = AdAccount(fbid='act_<AD_ACCOUNT_ID>')

params = {
    AdSet.Field.name: 'My First AdSet',
    AdSet.Field.daily_budget: 2000,
    AdSet.Field.start_time: '<START_TIME>',
    AdSet.Field.campaign_id: <CAMPAIGN_ID>,
    AdSet.Field.bid_amount: <BID_AMOUNT>,
    AdSet.Field.billing_event: <BILLING_EVENT>,
    AdSet.Field.optimization_goal: optimization_goal,
    AdSet.Field.targeting: <TARGETING>,
    AdSet.Field.status: AdSet.Status.active,
}
adset = ad_account.create_ad_set(params=params)
AdSet adSet = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdSet()
  .setName("My First AdSet")
  .setDailyBudget(2000L)
  .setStartTime(<START_TIME>)
  .setCampaignId(<CAMPAIGN_ID>)
  .setBidAmount(<BID_AMOUNT>)
  .setBillingEvent(<BILLING_EVENT>)
  .setOptimizationGoal(<BILLING_EVENT>)
  .setTargeting(
    new Targeting()
      .setFieldFacebookPositions(Arrays.asList("feed"))
      .setFieldGeoLocations(
        new TargetingGeoLocation()
          .setFieldCountries(Arrays.asList("US"))
      )
      .setFieldPublisherPlatforms(Arrays.asList("facebook", "audience_network"))
  )
  .setStatus(AdSet.EnumStatus.VALUE_PAUSED)
  .execute();
String ad_set_id = adSet.getId();
curl \
  -F 'name=My First AdSet' \
  -F 'daily_budget=2000' \
  -F 'start_time=<START_TIME>' \
  -F 'campaign_id=<CAMPAIGN_ID>' \
  -F 'bid_amount=<BID_AMOUNT>' \
  -F 'billing_event=<BILLING_EVENT>' \
  -F 'optimization_goal=<BILLING_EVENT>' \
  -F 'targeting={ 
    "facebook_positions": ["feed"], 
    "geo_locations": {"countries":["US"]}, 
    "publisher_platforms": ["facebook","audience_network"] 
  }' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/act_<AD_ACCOUNT_ID>/adsets

To set a lifetime budget of 200 dollars for a campaign setup to run for 10 days:

use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdSetFields;

$adset = new AdSet(null, 'act_<AD_ACCOUNT_ID>');
$adset->setData(array(
  AdSetFields::NAME => 'My First AdSet',
  AdSetFields::LIFETIME_BUDGET => '20000',
  AdSetFields::START_TIME => <START_TIME>,
  AdSetFields::END_TIME => <END_TIME>,
  AdSetFields::CAMPAIGN_ID => <CAMPAIGN_ID>,
  AdSetFields::BID_AMOUNT => <BID_AMOUNT>,
  AdSetFields::BILLING_EVENT => <BILLING_EVENT>,
  AdSetFields::OPTIMIZATION_GOAL => $optimization_goal,
  AdSetFields::TARGETING => <TARGETING>,
));

$adset->create(array(
  AdSet::STATUS_PARAM_NAME => AdSet::STATUS_PAUSED,
));
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.adset import AdSet

ad_account = AdAccount(fbid='act_<AD_ACCOUNT_ID>')

params = {
    AdSet.Field.name: 'My First AdSet',
    AdSet.Field.daily_budget: 20000,
    AdSet.Field.start_time: '<START_TIME>',
    AdSet.Field.end_time: '<END_TIME>',
    AdSet.Field.campaign_id: <CAMPAIGN_ID>,
    AdSet.Field.bid_amount: <BID_AMOUNT>,
    AdSet.Field.billing_event: <BILLING_EVENT>,
    AdSet.Field.optimization_goal: optimization_goal,
    AdSet.Field.targeting: <TARGETING>,
    AdSet.Field.status: AdSet.Status.paused,
}
adset = ad_account.create_ad_set(params=params)
AdSet adSet = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdSet()
  .setName("My First AdSet")
  .setLifetimeBudget(20000L)
  .setStartTime(<START_TIME>)
  .setEndTime(<END_TIME>)
  .setCampaignId(<CAMPAIGN_ID>)
  .setBidAmount(<BID_AMOUNT>)
  .setBillingEvent(<BILLING_EVENT>)
  .setOptimizationGoal(<BILLING_EVENT>)
  .setTargeting(
    new Targeting()
      .setFieldFacebookPositions(Arrays.asList("feed"))
      .setFieldGeoLocations(
        new TargetingGeoLocation()
          .setFieldCountries(Arrays.asList("US"))
      )
      .setFieldPublisherPlatforms(Arrays.asList("facebook", "audience_network"))
  )
  .setStatus(AdSet.EnumStatus.VALUE_PAUSED)
  .execute();
String ad_set_id = adSet.getId();
curl \
  -F 'name=My First AdSet' \
  -F 'lifetime_budget=20000' \
  -F 'start_time=<START_TIME>' \
  -F 'end_time=<END_TIME>' \
  -F 'campaign_id=<CAMPAIGN_ID>' \
  -F 'bid_amount=<BID_AMOUNT>' \
  -F 'billing_event=<BILLING_EVENT>' \
  -F 'optimization_goal=<BILLING_EVENT>' \
  -F 'targeting={ 
    "facebook_positions": ["feed"], 
    "geo_locations": {"countries":["US"]}, 
    "publisher_platforms": ["facebook","audience_network"] 
  }' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/act_<AD_ACCOUNT_ID>/adsets

If you choose daily budget, we pace your daily spending while a lifetime budget paces spending over an ad set's lifetime, see Ad Delivery and Pacing.

Optimization Goals

Define advertising goals you want to achieve when Facebook delivers your ads. We use your ad set's optimization_goal to decide which people get your ad. For example with APP_INSTALLS, Facebook delivers your ad to people who are more likely to install your app.

optimization_goal defaults to a goal associated with your objective. For example, if objective is APP_INSTALLS, optimization_goal defaults to APP_INSTALLS.

If you specify another optimization_goal, Facebook delivers your ad to as many daily unique people as possible, regardlesss of the probability anyone takes action towards your objective. See Validation Best Practices

In Marketing API v2.4, we replaced forms of bidding such as bid_type, bid_info, and conversion_specs, with new fields: optimization_goal, bid_amount, and billing_event. This decoupled campaign optimization such APP_INSTALLS or LINK_CLICKS from billing, such as charges per IMPRESSIONS, APP_INSTALLS, or LINK_CLICKS.

Bidding

A bid expresses how much you value your ad reaching a target audience and delivering results on your optimization_goal. bid_amount is the amount you want to spend to reach a given optimization_goal. At Facebook's ad auction, Facebook evaluates your bid_amount and the probability of reaching your optimization_goal. We apply an effective bid so you only win auctions and have your ads delivered when you are likely to reach your optimization_goal. See Ads Help Center, Ad Auction.

When you choose your bid:

  • Bid your true value: Think about your advertising objective and bid the maximum amount you're willing to pay for that objective.
  • Decide whether you want to maximize for profit or for growth

You can also set objective and billing_event but neither directly impact bid_amount or your effective bid. Your actual cost is usually equal or less than bid_amount; occasionally it may be a little higher, see Billing Event.

For example, use these setting to spend about $10.00 for 1,000 daily unique views:

  • Campaign objective: APP_INSTALLS
  • Ad set optimization_goal: REACH
  • Ad set billing_event: IMPRESSIONS

However, to spend $10.00 for each app install, use these settings:

  • Campaign objective: APP_INSTALLS
  • Ad set optimization_goal: APP_INSTALLS
  • Ad set billing_event: any valid option

billing_event does not affect auction prices directly; it indirectly affects your actual spending due to Ads Delivery Pacing.

Automatic Bidding

When you set is_autobid to true, Facebook calculates your actual bidding based on ads delivery pacing. Use this option if you lack a true value for reaching your advertising goal. Our delivery system adjusts your actual bid amount to achieve the most optimization_goals for your budget amount.

Campaign Budget Optimization

Campaign budget optimization is a way of optimizing the distribution of a campaign budget across your campaign's ad sets. This means Facebook automatically and continuously finds the best available opportunities for results across your ad sets and distributes your campaign budget in real time to get those results.

For more information, see:

Campaign budget optimization is launched in a closed beta. To request beta access, report any bugs, or send feedback, contact the Facebook Marketing Developers Community.

Campaign-Level Fields

  • daily_budget—The daily budget of the campaign.
  • lifetime_budget—The lifetime budget of the campaign.
  • pacing_type—Pacing type shared across the children ad sets. This field must be specified in the campaign level when using campaign budget. Available options: standard
  • is_autobid—Set whether to bid automatically.
  • is_average_price_pacing—Set whether the advertiser intends to use average price pacing. See explanation.

Ad Set-Level Controls

  • daily_min_spend_target—Daily minimum spend target of the ad set defined in your account currency. You must specify the daily budget in the campaign. This target is not a guarantee, but our best effort.
  • daily_spend_cap—Daily spend cap of the ad set defined in your account currency. You must specify the daily budget in the campaign.
  • lifetime_min_spend_target—Lifetime minimum spend target of the ad set defined in your account currency. You must specify the lifetime budget in the campaign. This target is not a guarantee, but our best effort.
  • lifetime_spend_cap—Lifetime spend cap of the ad set defined in your account currency. You must specify the lifetime budget in the campaign.
  • bid_amount—Bid amount for this ad set. Only available when the Campaign level is_autobid is false.

Examples

Campaign creation with $1000 USD daily budget

curl 
 -F "name"="L3 With Daily Budget" 
 -F "objective"="LINK_CLICKS" 
 -F "daily_budget=100000" 
 -F "access_token"="ACCESS_TOKEN" 
https://graph.facebook.com/AD_VERSION/act_AD_ACCOUNT_ID/campaigns

Campaign creation with $1000 USD lifetime budget

curl 
 -F "name"="L3 With Lifetime Budget" 
 -F "objective"="LINK_CLICKS" 
 -F "lifetime_budget=100000" 
 -F "is_autobid"="true"ACCESS_TOKEN" 
https://graph.facebook.com/AD_VERSION/act_AD_ACCOUNT_ID/campaigns

Ad Set Creation

curl \
 -F "campaign_id"="CAMPAIGN_ID" 
 -F "name"="Test Adset No Budget" 
 -F "status"="ACTIVE" 
 -F "optimization_goal"="LINK_CLICKS" 
 -F "targeting={'geo_locations':{'countries':['US']},'publisher_platforms':['facebook','audience_network'],'facebook_positions':['feed'],'device_platforms':['mobile','desktop']}" 
 -F "billing_event"="IMPRESSIONS" 
 -F "access_token"="ACCESS_TOKEN" 
https://graph.facebook.com/v2.9/act_AD_ACCOUNT_ID/adsets

Limitations and Best Practices

  • Bid strategy—Define the bid strategy at the campaign level; for example, define by maximum bid, auto bid, or average cost bid. All ad sets share the same bid strategy defined in the campaign level; you can define different bid amounts in an ad set level for non-auto bid campaigns.
  • Pacing—Define the pacing_type in the campaign level, not in the ad set level.
  • Optimization goals—All optimization goals must be the same across ad sets under auto bid. Once campaign is published, optimization goals can't be edited.
  • No accelerated delivery
  • No day parting
  • No 2-point optimization
  • Can't turn on or off campaign budget after creation

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:

use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdSetFields;

$adset = new AdSet(null, 'act_<AD_ACCOUNT_ID>');
$adset->setData(array(
  AdSetFields::NAME => 'My First AdSet',
  AdSetFields::LIFETIME_BUDGET => '20000',
  AdSetFields::START_TIME => '<START_TIME>',
  AdSetFields::END_TIME => '<END_TIME>',
  AdSetFields::CAMPAIGN_ID => <CAMPAIGN_ID>,
  AdSetFields::BID_AMOUNT => 500,
  AdSetFields::BILLING_EVENT => AdSetBillingEventValues::IMPRESSIONS,
  AdSetFields::OPTIMIZATION_GOAL =>
    AdSetOptimizationGoalValues::POST_ENGAGEMENT,
  AdSetFields::TARGETING => (new Targeting())->setData(array(
    TargetingFields::GEO_LOCATIONS => array(
      'countries' => array('JP'),
      'regions' => array(array('key' => '3886')),
      'cities' => array(array(
        'key' => '2420605',
        'radius' => 10,
        'distance_unit' => 'mile',
      )),
    ),
    TargetingFields::GENDERS => array(1),
    TargetingFields::AGE_MIN => 20,
    TargetingFields::AGE_MAX => 24,
    TargetingFields::INTERESTS => array(array(
      'id' => 6003107902433,
      'name' => 'Association football (Soccer)',
    )),
    TargetingFields::BEHAVIORS => array(array(
      'id' => 6002714895372,
      'name' => 'All travelers',
    )),
    TargetingFields::LIFE_EVENTS => array(array(
      'id' => 6002714398172,
      'name' => 'Newlywed (1 year)',
    )),
    'home_ownership' => array(array(
      'id' => 6006371327132,
      'name' => 'Renters',
    )),
    TargetingFields::PUBLISHER_PLATFORMS => array('facebook'),
    TargetingFields::DEVICE_PLATFORMS => array('desktop'),
  )),
));

$adset->create(array(
  AdSet::STATUS_PARAM_NAME => AdSet::STATUS_PAUSED,
));
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.adset import AdSet

ad_account = AdAccount(fbid='act_<AD_ACCOUNT_ID>')

params = {
    AdSet.Field.name: 'My First AdSet',
    AdSet.Field.daily_budget: 20000,
    AdSet.Field.start_time: <START_TIME>,
    AdSet.Field.end_time: <END_TIME>,
    AdSet.Field.campaign_id: <CAMPAIGN_ID>,
    AdSet.Field.bid_amount: 500,
    AdSet.Field.billing_event: AdSet.BillingEvent.impressions,
    AdSet.Field.optimization_goal: optimization_goal,
    AdSet.Field.targeting: {
        'geo_locations': {
            'countries': ['JP'],
            'regions': [{'key': '3886'}],
            'cities': [
                {
                    'key': '2420605',
                    'radius': 10,
                    'distance_unit': 'mile',
                },
            ],
        },
        'genders': [1],
        'age_min': 20,
        'age_max': 24,
        'interests': [
            {
                'id': 6003107902433,
                'name': 'Association football (Soccer)',
            },
        ],
        'behaviors': [{'id': 6002714895372, 'name': 'All travelers'}],
        'life_events': [{'id': 6002714398172, 'name': 'Newlywed (1 year)'}],
        'home_ownership': [{'id': 6006371327132, 'name': 'Renters'}],
        Targeting.Field.publisher_platforms: ['facebook'],
        Targeting.Field.device_platforms: ['desktop'],
    },
    'status': AdSet.Status.paused,
}
adset = ad_account.create_ad_set(params=params)
AdSet adSet = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdSet()
  .setName("My First AdSet")
  .setLifetimeBudget(20000L)
  .setStartTime(<START_TIME>)
  .setEndTime(<END_TIME>)
  .setCampaignId(<CAMPAIGN_ID>)
  .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("6002714895372")
          .setFieldName("All travelers")
      ))
      .setFieldDevicePlatforms(Arrays.asList(Targeting.EnumDevicePlatforms.VALUE_DESKTOP))
      .setFieldGenders(Arrays.asList(1L))
      .setFieldGeoLocations(
        new TargetingGeoLocation()
          .setFieldCities(Arrays.asList(
            new TargetingGeoLocationCity()
              .setFieldDistanceUnit("mile")
              .setFieldKey("2420605")
              .setFieldRadius(10L)
          ))
          .setFieldCountries(Arrays.asList("JP"))
          .setFieldRegions(Arrays.asList(
            new TargetingGeoLocationRegion()
              .setFieldKey("3886")
          ))
      )
      .setFieldHomeOwnership(Arrays.asList(
        new IDName()
          .setFieldId("6006371327132")
          .setFieldName("Renters")
      ))
      .setFieldInterests(Arrays.asList(
        new IDName()
          .setFieldId("6003107902433")
          .setFieldName("Association football (Soccer)")
      ))
      .setFieldLifeEvents(Arrays.asList(
        new IDName()
          .setFieldId("6002714398172")
          .setFieldName("Newlywed (1 year)")
      ))
      .setFieldPublisherPlatforms(Arrays.asList("facebook"))
  )
  .setStatus(AdSet.EnumStatus.VALUE_PAUSED)
  .execute();
String ad_set_id = adSet.getId();
curl \
  -F 'name=My First AdSet' \
  -F 'lifetime_budget=20000' \
  -F 'start_time=<START_TIME>' \
  -F 'end_time=<END_TIME>' \
  -F 'campaign_id=<CAMPAIGN_ID>' \
  -F 'bid_amount=500' \
  -F 'billing_event=IMPRESSIONS' \
  -F 'optimization_goal=POST_ENGAGEMENT' \
  -F 'targeting={ 
    "age_max": 24, 
    "age_min": 20, 
    "behaviors": [{"id":6002714895372,"name":"All travelers"}], 
    "device_platforms": ["desktop"], 
    "genders": [1], 
    "geo_locations": { 
      "countries": ["JP"], 
      "regions": [{"key":"3886"}], 
      "cities": [ 
        { 
          "key": "2420605", 
          "radius": 10, 
          "distance_unit": "mile" 
        } 
      ] 
    }, 
    "home_ownership": [{"id":6006371327132,"name":"Renters"}], 
    "interests": [{"id":6003107902433,"name":"Association football (Soccer)"}], 
    "life_events": [{"id":6002714398172,"name":"Newlywed (1 year)"}], 
    "publisher_platforms": ["facebook"] 
  }' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/act_<AD_ACCOUNT_ID>/adsets

Once you select optimization_goal, you may have one or more billing_event options. See Marketing API Validation: 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. For 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 people see your ad and you spend $100.00, it's possible only .5%, or 5 people 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.

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.

Here's another 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 people 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.

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.

FAQ

For Mobile App Install ads, if I have billing_event as IMPRESSIONS, can I get more impressions without a high rate of install? Alternately, if I use APP_INSTALLS, can I get higher installs but at higher cost?

Regardless of billing_event, if optimization_goal is APP_INSTALLS, we deliver your ads to people we predict have a higher chance of installing your app. We do not consider billing_event when we delivery ads. billing_event only impacts delivery through pacing if your budget is limited. Performance in either case is close, while you risk uneven delivery or a slightly higher cost per install due to variance in action predictions and actual actions.

What events does POST_ENGAGEMENT cover?

Most actions in an ad, including link clicks, app installs, video viewing over a certain period, tag photo, like, comment, share, and so on.

What’s the relationship between the optimization_goal, billing_event and CPC, CPA, oCPM?

See v2.4 Optimization Simplification.

Ad Sets Budget Rebalancing

Ad Set Budget Balancing lets Facebook automatically move budget between Ad Sets in a Campaign once a day around midnight in your time zone. Move budgets from Ad Sets experiencing under-delivery to budget-constrained Ad Sets that can deliver more impressions. Facebook determines delivery rate based on target spend and actual spend at different times.

To use this feature, you need Ad Sets:

  • Under the same Campaign.
  • That run at least 10 hours per day.
  • With the same budget type: daily or lifetime budget.
  • That are active at the time of rebalancing.

Budgets are rebalanced between Ad Set, but you enable it with budget_rebalance_flag on a Campaign object. All Ad Sets in the campaign are affected. Set this field using the API call below.

curl -i -X POST \
-d "budget_rebalance_flag=true" \
-d "access_token=<ACCESS_TOKEN>" \
https://graph.facebook.com/v2.7/<CAMPAIGN_ID>

You can also set budget_rebalance_flag on Campaign creation. See Ads Management Quickstart.

Tracking Specs

Tracking specs help you track actions taken by users interacting with your ad. Tracking specs only track; they do not optimize ads delivery for an action or charge you based on that action.

You can use tracking specs with any bid type and creative. To specify tracking specs use the ad field, tracking_specs.

We automatically select a default tracking spec set based on your objective, but you can track additional actions. For example, a link page post ad with POST_ENGAGEMENT objective defaults to post_engagement tracking, but you setup a Facebook pixel on the offsite page and track other actions.

The default tracking spec for the page post engagement objective is action.type = post_engagement with ids for the post and page:

use FacebookAds\Object\Ad;
use FacebookAds\Object\Fields\AdFields;

$ad = new Ad(null, 'act_<AD_ACCOUNT_ID>');
$ad->setData(array(
  AdFields::NAME => 'My First Ad',
  AdFields::ADSET_ID => <AD_SET_ID>,
  AdFields::CREATIVE => array(
  'creative_id' => <CREATIVE_ID>,
  ),
  AdFields::TRACKING_SPECS => array(
  'action.type' => 'post_engagement',
  'post' => <POST_ID>,
  'page' => <PAGE_ID>,
),
));

$ad->create(array(
  Ad::STATUS_PARAM_NAME => Ad::STATUS_PAUSED,
));
from facebookads.adobjects.ad import Ad

ad = Ad(parent_id='act_<AD_ACCOUNT_ID>')
ad[Ad.Field.name] = 'My First Ad'
ad[Ad.Field.adset_id] = <AD_SET_ID>
ad[Ad.Field.creative] = {'creative_id': <CREATIVE_ID>}
ad[Ad.Field.tracking_specs] = {
    'action.type': 'post_engagement',
    'post': '<POST_ID>',
    'page': '<PAGE_ID>',
}

ad.remote_create()
Ad ad = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAd()
  .setName("My First Ad")
  .setAdsetId(<AD_SET_ID>)
  .setCreative(
    new AdCreative()
      .setFieldId(<CREATIVE_ID>)
  )
  .setTrackingSpecs("{\"action.type\":\"post_engagement\",\"post\":\"" + <POST_ID> + "\",\"page\":\"" + <PAGE_ID> + "\"}")
  .setStatus(Ad.EnumStatus.VALUE_PAUSED)
  .execute();
String ad_id = ad.getId();
curl \
  -F 'name=My First Ad' \
  -F 'adset_id=<AD_SET_ID>' \
  -F 'creative={"creative_id":"<CREATIVE_ID>"}' \
  -F 'tracking_specs={ 
    "action.type": "post_engagement", 
    "post": "<POST_ID>", 
    "page": "<PAGE_ID>" 
  }' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.10/act_<AD_ACCOUNT_ID>/ads

For custom tracking specs, see Tracking Specs, Custom.

Resources