Marketing API Version

Video and Carousel Ads

You can easily create, measure, and optimize video and carousel ads on Facebook through the API. See Facebook for Business, Carousel Ads. For supported video formats for ads, see Advertiser Help Center, Videos.

Video Ads

To create a video ad in a VIDEO_VIEWS objective and optimize the bid for reach, follow these steps:

Create ad creatives

Create a video ad using an existing video ID and a video uploaded to Facebook via ad account video library or with page video feed.

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\AdCreativeVideoData;
use FacebookAds\Object\Fields\AdCreativeVideoDataFields;
use FacebookAds\Object\AdCreativeObjectStorySpec;
use FacebookAds\Object\Fields\AdCreativeObjectStorySpecFields;
use FacebookAds\Object\Fields\AdCreativeFields;


$video_data = new AdCreativeVideoData();
$video_data->setData(array(
  AdCreativeVideoDataFields::DESCRIPTION => 'Try it out',
  AdCreativeVideoDataFields::IMAGE_URL => '<THUMBNAIL_URL>',
  AdCreativeVideoDataFields::VIDEO_ID => <VIDEO_ID>,
));

$object_story_spec = new AdCreativeObjectStorySpec();
$object_story_spec->setData(array(
  AdCreativeObjectStorySpecFields::PAGE_ID => <PAGE_ID>,
  AdCreativeObjectStorySpecFields::VIDEO_DATA => $video_data,
));

$creative = new AdCreative(null, 'act_<AD_ACCOUNT_ID>');

$creative->setData(array(
  AdCreativeFields::NAME => 'Sample Creative',
  AdCreativeFields::OBJECT_STORY_SPEC => $object_story_spec,
));

$creative->create();
from facebookads.adobjects.adcreative import AdCreative
from facebookads.adobjects.adcreativeobjectstoryspec \
    import AdCreativeObjectStorySpec
from facebookads.adobjects.adcreativevideodata \
    import AdCreativeVideoData

video_data = AdCreativeVideoData()
video_data[AdCreativeVideoData.Field.description] = 'My Description'
video_data[AdCreativeVideoData.Field.video_id] = <VIDEO_ID>
video_data[AdCreativeVideoData.Field.image_url] = '<IMAGE_URL>'

object_story_spec = AdCreativeObjectStorySpec()
object_story_spec[AdCreativeObjectStorySpec.Field.page_id] = <PAGE_ID>
object_story_spec[AdCreativeObjectStorySpec.Field.video_data] = video_data

creative = AdCreative(parent_id='act_<AD_ACCOUNT_ID>')
creative[AdCreative.Field.name] = 'Video Ad Creative'
creative[AdCreative.Field.object_story_spec] = object_story_spec
creative.remote_create()
AdCreative adCreative = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdCreative()
  .setName("Sample Creative")
  .setObjectStorySpec(
    new AdCreativeObjectStorySpec()
      .setFieldPageId(<PAGE_ID>)
      .setFieldVideoData(
        new AdCreativeVideoData()
          .setFieldDescription("Try it out")
          .setFieldImageUrl(<THUMBNAIL_URL>)
          .setFieldVideoId(<VIDEO_ID>)
      )
  )
  .execute();
String ad_creative_id = adCreative.getId();
curl \
  -F 'name=Sample Creative' \
  -F 'object_story_spec={ 
    "page_id": "<PAGE_ID>", 
    "video_data": { 
      "description": "Try it out", 
      "image_url": "<THUMBNAIL_URL>", 
      "video_id": "<VIDEO_ID>" 
    } 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/adcreatives
Reference: Ad Creative

Slideshow

To extend or launch brand campaigns to basic feature phones in emerging markets or to create a simple video, try image slideshows. Upload images into a video asset. See Create Slideshow. For example:

use FacebookAds\Object\AdVideo;
use FacebookAds\Object\Fields\AdVideoFields;

$video = new AdVideo(null, 'act_<AD_ACCOUNT_ID>');
$video->{AdVideoFields::SLIDESHOW_SPEC} = array (
  'images_urls' => array(
    '<IMAGE_URL_1>',
    '<IMAGE_URL_2>',
    '<IMAGE_URL_3>',
  ),
  'duration_ms' => 2000,
  'transition_ms' => 200,
);

$video->create();
from facebookads.adobjects.advideo import AdVideo
from facebookads.specs import SlideshowSpec

video = AdVideo(parent_id='act_<AD_ACCOUNT_ID>')
slideshow = SlideshowSpec()
slideshow.update({
    SlideshowSpec.Field.images_urls: <IMAGE_URLS>,
    SlideshowSpec.Field.duration_ms: 2000,
    SlideshowSpec.Field.transition_ms: 200,
})

video[AdVideo.Field.slideshow_spec] = slideshow
video.remote_create()
new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdVideo()
  .setSlideshowSpec("{\"images_urls\":[\"" + <IMAGE_URL_1> + "\",\"" + <IMAGE_URL_2> + "\",\"" + <IMAGE_URL_3> + "\"],\"duration_ms\":\"2000\",\"transition_ms\":\"200\"}")
  .execute();
curl \
  -F 'slideshow_spec={ 
    "images_urls": [ 
      "<IMAGE_URL_1>", 
      "<IMAGE_URL_2>", 
      "<IMAGE_URL_3>" 
    ], 
    "duration_ms": 2000, 
    "transition_ms": 200 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph-video.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/advideos

See Video Creative Best Practices and Reference: Ad Video Library.

2. Create ad campaigns

Set objective to VIDEO_VIEWS:

use FacebookAds\Object\Campaign;
use FacebookAds\Object\Fields\CampaignFields;
use FacebookAds\Object\Values\CampaignObjectiveValues;

$campaign = new Campaign(null, 'act_<AD_ACCOUNT_ID>');
$campaign->setData(array(
  CampaignFields::NAME => 'Video Views Campaign',
  CampaignFields::OBJECTIVE => CampaignObjectiveValues::VIDEO_VIEWS,
));

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

campaign = Campaign(parent_id='act_<AD_ACCOUNT_ID>')
campaign.update({
    Campaign.Field.name: 'Video Views Campaign',
    Campaign.Field.objective: Campaign.Objective.video_views,
})

campaign.remote_create(params={
    'status': Campaign.Status.paused,
})
print(campaign)
Campaign campaign = new AdAccount(act_<AD_ACCOUNT_ID>, context).createCampaign()
  .setName("Video Views Campaign")
  .setObjective(Campaign.EnumObjective.VALUE_VIDEO_VIEWS)
  .setStatus(Campaign.EnumStatus.VALUE_PAUSED)
  .execute();
String campaign_id = campaign.getId();
curl \
  -F 'name=Video Views Campaign' \
  -F 'objective=VIDEO_VIEWS' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/campaigns

See Reference: Campaign, AdObjectives in PHP and AdObjectives in Python

3. Create an ad set

If your goals is lowest cost-per-view possible, you should pair the video view campaign objective with an ad set's optimization_goal=VIDEO_VIEWS. You can bid bidding_event IMPRESSIONS or VIDEO_VIEWS to pay per impression or per video view. See CPV bidding.

use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdSetFields;
use FacebookAds\Object\Fields\TargetingFields;
use FacebookAds\Object\Targeting;
use FacebookAds\Object\Values\AdSetBillingEventValues;
use FacebookAds\Object\Values\AdSetOptimizationGoalValues;

$adset = new AdSet(null, 'act_<AD_ACCOUNT_ID>');
$adset->setData(array(
  AdSetFields::NAME => 'A CPV Ad Set',
  AdSetFields::CAMPAIGN_ID => <CAMPAIGN_ID>,
  AdSetFields::DAILY_BUDGET => 500,
  AdSetFields::START_TIME =>
    (new \DateTime("+1 week"))->format(\DateTime::ISO8601),
  AdSetFields::END_TIME =>
    (new \DateTime("+2 week"))->format(\DateTime::ISO8601),
  AdSetFields::BILLING_EVENT => AdSetBillingEventValues::VIDEO_VIEWS,
  AdSetFields::OPTIMIZATION_GOAL => AdSetOptimizationGoalValues::VIDEO_VIEWS,
  AdSetFields::BID_AMOUNT => 100,
  AdSetFields::TARGETING => (new Targeting())->setData(array(
    TargetingFields::GEO_LOCATIONS => array(
      'countries' => array(
        'US',
      ),
    ),
    TargetingFields::PUBLISHER_PLATFORMS => array('facebook'),
    TargetingFields::DEVICE_PLATFORMS => array('mobile'),
  )),
));

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

adset = AdSet(parent_id='act_<AD_ACCOUNT_ID>')
adset.update({
    AdSet.Field.name: 'A CPV Ad Set',
    AdSet.Field.campaign_id: <CAMPAIGN_ID>,
    AdSet.Field.daily_budget: 500,
    AdSet.Field.start_time: int(time.time()),
    AdSet.Field.end_time: int(time.time() + 100000),
    AdSet.Field.optimization_goal: AdSet.OptimizationGoal.video_views,
    AdSet.Field.billing_event: AdSet.BillingEvent.video_views,
    AdSet.Field.bid_amount: 100,
    AdSet.Field.targeting: {
        'geo_locations': {
            'countries': ['US'],
        },
        Targeting.Field.publisher_platforms: ['facebook'],
        Targeting.Field.device_platforms: ['mobile'],
    },
})

adset.remote_create(params={
    'status': AdSet.Status.paused,
})
AdSet adSet = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdSet()
  .setName("A CPV Ad Set")
  .setCampaignId(<CAMPAIGN_ID>)
  .setDailyBudget(500L)
  .setStartTime(start_time)
  .setEndTime(end_time)
  .setBillingEvent(AdSet.EnumBillingEvent.VALUE_VIDEO_VIEWS)
  .setOptimizationGoal(AdSet.EnumOptimizationGoal.VALUE_VIDEO_VIEWS)
  .setBidAmount(100L)
  .setTargeting(
    new Targeting()
      .setFieldDevicePlatforms(Arrays.asList(Targeting.EnumDevicePlatforms.VALUE_MOBILE))
      .setFieldGeoLocations(
        new TargetingGeoLocation()
          .setFieldCountries(Arrays.asList("US"))
      )
      .setFieldPublisherPlatforms(Arrays.asList("facebook"))
  )
  .setStatus(AdSet.EnumStatus.VALUE_PAUSED)
  .execute();
String ad_set_id = adSet.getId();
curl \
  -F 'name=A CPV Ad Set' \
  -F 'campaign_id=<CAMPAIGN_ID>' \
  -F 'daily_budget=500' \
  -F 'start_time=2017-02-03T14:13:58+0000' \
  -F 'end_time=2017-02-10T14:13:58+0000' \
  -F 'billing_event=VIDEO_VIEWS' \
  -F 'optimization_goal=VIDEO_VIEWS' \
  -F 'bid_amount=100' \
  -F 'targeting={ 
    "device_platforms": ["mobile"], 
    "geo_locations": {"countries":["US"]}, 
    "publisher_platforms": ["facebook"] 
  }' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/adsets

Cost-per-view rates are lower for ad sets with optimization_goal=VIDEO_VIEWS compared to CPVs from Reach and Frequency buying optimized for video views. See Reference: Ad Set.

5. Create an ad

Use the existing ad set and ad creative:

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

$data = array(
  AdFields::NAME => 'My Ad',
  AdFields::ADSET_ID => <AD_SET_ID>,
  AdFields::CREATIVE => array(
    'creative_id' => <CREATIVE_ID>,
  ),
);

$ad = new Ad(null, 'act_<AD_ACCOUNT_ID>');
$ad->setData($data);
$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 Ad'
ad[Ad.Field.adset_id] = <AD_SET_ID>
ad[Ad.Field.creative] = {
    'creative_id': <CREATIVE_ID>,
}
ad.remote_create(params={
    'status': Ad.Status.paused,
})
Ad ad = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAd()
  .setName("My Ad")
  .setAdsetId(<AD_SET_ID>)
  .setCreative(
    new AdCreative()
      .setFieldId(<CREATIVE_ID>)
  )
  .setStatus(Ad.EnumStatus.VALUE_PAUSED)
  .execute();
curl \
  -F 'name=My Ad' \
  -F 'adset_id=<AD_SET_ID>' \
  -F 'creative={"creative_id":"<CREATIVE_ID>"}' \
  -F 'status=PAUSED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/ads

When a campaign objective is VIDEO_VIEWS, by default the ad gets the right tracking specs which define actions tracked for an ad. For example, video views:

{'action.type':'video_view','post':'POST_ID','post.wall':'PAGE_ID'}

See Ads Manager: My Campaigns and Reference: Ad.

Example Brand Awareness

To create a video ad for brand awareness, see brand awareness blog.

Example Reach and Frequency

To extend the reach of a video to more people, use the video view campaign objective with Reach and Frequency. You will need to create a prediction, reserve it, and assign it to your ad set.

Follow the video view creation but apply Reach and Frequency to your ad set. Specify these additional parameters:

$adset->{AdSetFields::RF_PREDICTION_ID} = <RESERVATION_ID>;
adset[AdSet.Field.prediction_id] = <RESERVATION_ID>
-F "rf_prediction_id=<RESERVATION_ID>" \

See Reference: Reach and Frequency

Video for Direct Response

Encourage people to move from awareness to action, see Video Creative in the Carousel Format.

  • Reach people who watched a video. From awareness to affinity and consideration. See remarketing.
  • Engage with brand and products. Add a call-to-action to visit a specific page on your website. See call to action.

Remarketing

Video ads remarketing provides support for advertisers to target certain custom audiences from organic or paid videos on both Facebook and Instagram. Use this feature to move people from awareness to deeper funnel objectives such as affinity and consideration. See Research: Creative Combinations that Work.

You need advertiser permission for the page containing a video to create an audience for that video.

For the audience, set subtype=ENGAGEMENT. Then write rules for the audience you want to create. Each rule has an object_id, such as video ID, and event_name. The event_name is one of:

  • video_watched: the number of times your video was watched for an aggregate of at least 3 seconds, or for nearly its total length, whichever happened first.
  • video_completed: the number of times your video was watched at 95% of its length, including watches that skipped to this point.
  • video_view_10s: the number of times your video was watched for an aggregate of at least 10 seconds, or for nearly its total length, whichever happened first.
  • video_view_25_percent: the number of times your video was watched at 25% of its length, including watches that skipped to this point.
  • video_view_50_percent: the number of times your video was watched at 50% of its length, including watches that skipped to this point.
  • video_view_75_percent: the number of times your video was watched at 75% of its length, including watches that skipped to this point.

You can combine videos to create an audience based on various videos and actions. For example, an audience could contain 3 second views from video A, and completes from video B and C.

This creates an audience from the past 14 days of 3s+ video viewers of video 1 and completed video viewers of video 2. The audience also autofills for viewers prior to audience creation with prefill=true.

use FacebookAds\Object\CustomAudience;
use FacebookAds\Object\Fields\CustomAudienceFields;


$audience = new CustomAudience(null, $ad_account_id);
$audience->setData(array(
  CustomAudienceFields::NAME => 'Video Ads Engagement Audience',
  CustomAudienceFields::SUBTYPE => 'ENGAGEMENT',
  CustomAudienceFields::DESCRIPTION => 'Users who watched my video',
  CustomAudienceFields::PREFILL => true,
  CustomAudienceFields::RULE => array(
    array(
      'object_id' => $video_id_1,
      'event_name' => 'video_watched',
    ),
    array(
      'object_id' => $video_id_2,
      'event_name' => 'video_completed',
    ),
  ),
));

$audience->create();
from facebookads.adobjects.customaudience import CustomAudience

audience = CustomAudience(parent_id=ad_account_id)
audience[CustomAudience.Field.subtype] = CustomAudience.Subtype.engagement
audience[CustomAudience.Field.name] = 'Video Ads Engagement Audience'
audience[CustomAudience.Field.description] = 'Users who watched my video'
audience[CustomAudience.Field.prefill] = True
audience[CustomAudience.Field.rule] = [
    {
        "object_id": video_id_1,
        "event_name": "video_watched",
    },
    {
        "object_id": video_id_2,
        "event_name": "video_completed",
    },
]
audience.remote_create()
curl \
  -F 'name=Video Ads Engagement Audience' \
  -F 'subtype=ENGAGEMENT' \
  -F 'description=Users who watched my video' \
  -F 'prefill=1' \
  -F 'rule=[ 
    {"object_id":"%video_id_1","event_name":"video_watched"}, 
    {"object_id":"%video_id_2","event_name":"video_completed"} 
  ]' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/%ad_account_id/customaudiences

Backfill supported for video views after October 16th, 2015.

Call to Action

Video with Call to Action (CTA) prompts people to learn more and visit a specific page on a website. Improve performance when your primary objective is driving video views or brand awareness and your secondary objective is driving offsite clicks. You should use a video link ad for the latter. How CTAs render:

  • For Mobile and Desktop, shown as part of the post. When the video is paused, it displays next to the Resume option.
  • For Mobile, when someone clicks a video to watch in full screen, a floating CTA appears as a video overlay.
  • External video link posts do not display CTAs.

You can use video with CTAs only with the following campaign objectives:

See Video expansion to Additional Objectives. This creates a video ad with GET_DIRECTIONS:

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Fields\AdCreativeVideoDataFields;
use FacebookAds\Object\Fields\AdCreativeObjectStorySpecFields;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\AdCreativeVideoData;
use FacebookAds\Object\AdCreativeObjectStorySpec;
use FacebookAds\Object\Values\AdCreativeCallToActionTypeValues;

$video_data = new AdCreativeVideoData();
$video_data->setData(array(
  AdCreativeVideoDataFields::IMAGE_URL => '<THUMBNAIL_URL>',
  AdCreativeVideoDataFields::VIDEO_ID => <VIDEO_ID>,
  AdCreativeVideoDataFields::DESCRIPTION =>
    "Come check out our new store in Menlo Park!",
  AdCreativeVideoDataFields::CALL_TO_ACTION => array(
    'type' => AdCreativeCallToActionTypeValues::GET_DIRECTIONS,
    'value' => array(
      'link' => 'fbgeo://37.48327, -122.15033, "1601 Willow Rd Menlo Park CA"',
    ),
  ),
));

$story = new AdCreativeObjectStorySpec();
$story->setData(array(
  AdCreativeObjectStorySpecFields::PAGE_ID => <PAGE_ID>,
  AdCreativeObjectStorySpecFields::VIDEO_DATA => $video_data,
));

$creative = new AdCreative(null, 'act_<AD_ACCOUNT_ID>');
$creative->{AdCreativeFields::OBJECT_STORY_SPEC} = $story;
$creative->create();
from facebookads.adobjects.adcreativevideodata import AdCreativeVideoData
from facebookads.adobjects.adcreative import AdCreative
from facebookads.adobjects.adcreativeobjectstoryspec \
    import AdCreativeObjectStorySpec

video_data = AdCreativeVideoData()
video_data[AdCreativeVideoData.Field.image_url] = image_url
video_data[AdCreativeVideoData.Field.video_id] = <VIDEO_ID>
video_data[AdCreativeVideoData.Field.description]\
    = 'Come check out our new store in Menlo Park!'
video_data[AdCreativeVideoData.Field.call_to_action] = {
    'type': 'GET_DIRECTIONS',
    'value': {
        'link': 'fbgeo://37.48327, -122.15033, "1601 Willow Rd Menlo Park CA"',
    },
}

story = AdCreativeObjectStorySpec()
story[AdCreativeObjectStorySpec.Field.page_id] = <PAGE_ID>
story[AdCreativeObjectStorySpec.Field.video_data] = video_data

creative = AdCreative(parent_id='act_<AD_ACCOUNT_ID>')
creative[AdCreative.Field.object_story_spec] = story
creative.remote_create()
AdCreative adCreative = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdCreative()
  .setObjectStorySpec(
    new AdCreativeObjectStorySpec()
      .setFieldPageId(<PAGE_ID>)
      .setFieldVideoData(
        new AdCreativeVideoData()
          .setFieldCallToAction(
            new AdCreativeLinkDataCallToAction()
              .setFieldType(AdCreativeLinkDataCallToAction.EnumType.VALUE_GET_DIRECTIONS)
              .setFieldValue(
                new AdCreativeLinkDataCallToActionValue()
                  .setFieldLink("fbgeo://37.48327, -122.15033, \"1601 Willow Rd Menlo Park CA\"")
              )
          )
          .setFieldDescription("Come check out our new store in Menlo Park!")
          .setFieldImageUrl(<THUMBNAIL_URL>)
          .setFieldVideoId(<VIDEO_ID>)
      )
  )
  .execute();
String ad_creative_id = adCreative.getId();
curl \
  -F 'object_story_spec={ 
    "page_id": "<PAGE_ID>", 
    "video_data": { 
      "call_to_action": { 
        "type": "GET_DIRECTIONS", 
        "value": { 
          "link": "fbgeo:\/\/37.48327, -122.15033, \"1601 Willow Rd Menlo Park CA\"" 
        } 
      }, 
      "description": "Come check out our new store in Menlo Park!", 
      "image_url": "<THUMBNAIL_URL>", 
      "video_id": "<VIDEO_ID>" 
    } 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/adcreatives

Video Metrics

Video Post Insights, Organic

Learn more about how your videos perform on Facebook and make more informed decisions about video content. Currently we only provide metrics when someone starts watching videos. This includes video views, unique video views, the average duration of the video view, and audience retention. See where people drop off in your videos and parts people may find most interesting. See Reference: Video Post Insights

Video Ad Insights, Paid

Use the Ad Insights API. The response contains various video metrics.

Video Type

Retrieve video ad stats grouped by video type such as auto-play, click-to-play. Include action_video_type in action_breakdowns. Expected values for action_video_type are total, click_to_play, and auto_play.

We are currently in limited testing for the action_video_type option. To identify clients with the breakdown, check CAN_USE_VIDEO_METRICS_BREAKDOWN for the ad account.

use FacebookAds\Object\AdAccount;
use FacebookAds\Object\Fields\AdsInsightsFields;
use FacebookAds\Object\Values\AdsInsightsActionBreakdownsValues;
use FacebookAds\Object\Values\AdsInsightsDatePresetValues;

$account = new AdAccount('act_<AD_ACCOUNT_ID>');

$params = array(
  'action_breakdowns' => AdsInsightsActionBreakdownsValues::ACTION_VIDEO_TYPE,
  'date_preset' => AdsInsightsDatePresetValues::LAST_30_DAYS,
);

$fields = array(
  AdsInsightsFields::ACTIONS,
  AdsInsightsFields::VIDEO_AVG_PCT_WATCHED_ACTIONS,
  AdsInsightsFields::VIDEO_COMPLETE_WATCHED_ACTIONS,
);

$stats = $account->getInsights($fields, $params);
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.adsinsights import AdsInsights

account = AdAccount('act_<AD_ACCOUNT_ID>')

params = {
    'action_breakdowns': AdsInsights.ActionBreakdowns.action_video_type,
    'date_preset': AdsInsights.DatePreset.last_30_days,
    'fields': [
        AdsInsights.Field.actions,
        AdsInsights.Field.video_avg_pct_watched_actions,
        AdsInsights.Field.video_complete_watched_actions,
    ],
}

stats = account.get_insights(params=params)
print(stats)
APINodeList<AdsInsights> adsInsightss = new AdAccount(act_<AD_ACCOUNT_ID>, context).getInsights()
  .setActionBreakdowns("action_video_type")
  .setDatePreset(AdsInsights.EnumDatePreset.VALUE_LAST_30_DAYS)
  .requestField("actions")
  .requestField("video_avg_pct_watched_actions")
  .requestField("video_complete_watched_actions")
  .execute();
curl -G \
  -d 'action_breakdowns=action_video_type' \
  -d 'date_preset=last_30_days' \
  -d 'fields=actions,video_avg_pct_watched_actions,video_complete_watched_actions' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/insights

The response includes objects with action_type as video_view and contain a key action_video_type:

{
  "data": [
    {
      "actions": [
        ...
        {
          "action_type": "video_play", 
          "value": 9898
        }, 
        {
          "action_type": "video_view", 
          "action_video_type": "total", 
          "value": 921129
        }, 
        {
          "action_type": "video_view", 
          "action_video_type": "auto_play", 
          "value": 915971
        }, 
        {
          "action_type": "video_view", 
          "action_video_type": "click_to_play", 
          "value": 5158
        }
      ], 
      "video_avg_pct_watched_actions": [
        {
          "action_type": "video_view", 
          "action_video_type": "total", 
          "value": 60.59
        }, 
        {
          "action_type": "video_view", 
          "action_video_type": "auto_play", 
          "value": 60.47
        }, 
        {
          "action_type": "video_view", 
          "action_video_type": "click_to_play", 
          "value": 80.63
        }
      ], 
      "video_complete_watched_actions": [
        {
          "action_type": "video_view", 
          "action_video_type": "total", 
          "value": 156372
        }, 
        {
          "action_type": "video_view", 
          "action_video_type": "auto_play", 
          "value": 154015
        }, 
        {
          "action_type": "video_view", 
          "action_video_type": "click_to_play", 
          "value": 2357
        }
      ], 
      "date_start": "2014-12-26", 
      "date_stop": "2015-03-25"
    }
  ], 
  "paging": {
    "cursors": {
      "before": "MA==", 
      "after": "MA=="
    }
  }
}

See Ad Insights API

Carousel Ads

Get more creative real-estate in News Feed and drive people to your website or mobile app to convert. Create a carousel ad two ways:

  1. Create an ad and unpublished page post in one call: ad creative API.
  2. Create an unpublished Page post then create an ad creative using the post (not available for video carousel).

Create Inline

Create a carousel ad page post while creating an ad creative. Specify the page post content in object_story_spec, which creates an unpublished page post from adcreatives. See ad creatives. For example:

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\Fields\AdCreativeLinkDataFields;
use FacebookAds\Object\Fields\AdCreativeObjectStorySpecFields;
use FacebookAds\Object\Fields\AdCreativeLinkDataChildAttachmentFields;
use FacebookAds\Object\AdCreativeLinkDataChildAttachment;
use FacebookAds\Object\AdCreativeLinkData;
use FacebookAds\Object\AdCreativeObjectStorySpec;

$product1 = (new AdCreativeLinkDataChildAttachment())->setData(array(
  AdCreativeLinkDataChildAttachmentFields::LINK =>
    'https://www.link.com/product1',
  AdCreativeLinkDataChildAttachmentFields::NAME => 'Product 1',
  AdCreativeLinkDataChildAttachmentFields::DESCRIPTION => '$8.99',
  AdCreativeLinkDataChildAttachmentFields::IMAGE_HASH => '<IMAGE_HASH>',
  AdCreativeLinkDataChildAttachmentFields::VIDEO_ID => '<VIDEO_ID>',
));

$product2 = (new AdCreativeLinkDataChildAttachment())->setData(array(
  AdCreativeLinkDataChildAttachmentFields::LINK =>
    'https://www.link.com/product2',
  AdCreativeLinkDataChildAttachmentFields::NAME => 'Product 2',
  AdCreativeLinkDataChildAttachmentFields::DESCRIPTION => '$9.99',
  AdCreativeLinkDataChildAttachmentFields::IMAGE_HASH => '<IMAGE_HASH>',
  AdCreativeLinkDataChildAttachmentFields::VIDEO_ID => '<VIDEO_ID>',
));

$product3 = (new AdCreativeLinkDataChildAttachment())->setData(array(
  AdCreativeLinkDataChildAttachmentFields::LINK =>
    'https://www.link.com/product3',
  AdCreativeLinkDataChildAttachmentFields::NAME => 'Product 3',
  AdCreativeLinkDataChildAttachmentFields::DESCRIPTION => '$10.99',
  AdCreativeLinkDataChildAttachmentFields::IMAGE_HASH => '<IMAGE_HASH>',
));

$link_data = new AdCreativeLinkData();
$link_data->setData(array(
  AdCreativeLinkDataFields::LINK => '<URL>',
  AdCreativeLinkDataFields::CAPTION => 'My caption',
  AdCreativeLinkDataFields::CHILD_ATTACHMENTS => array(
    $product1, $product2, $product3,
  ),
));

$object_story_spec = new AdCreativeObjectStorySpec();
$object_story_spec->setData(array(
  AdCreativeObjectStorySpecFields::PAGE_ID => <PAGE_ID>,
  AdCreativeObjectStorySpecFields::LINK_DATA => $link_data,
));

$creative = new AdCreative(null, 'act_<AD_ACCOUNT_ID>');
$creative->setData(array(
  AdCreativeFields::NAME => 'Sample Creative',
  AdCreativeFields::OBJECT_STORY_SPEC => $object_story_spec,
));

$creative->create();
from facebookads.adobjects.adcreative import AdCreative
from facebookads.adobjects.adcreativelinkdata import AdCreativeLinkData
from facebookads.adobjects.adcreativeobjectstoryspec \
    import AdCreativeObjectStorySpec
from facebookads.adobjects.adcreativelinkdatachildattachment \
    import AdCreativeLinkDataChildAttachment

product1 = AdCreativeLinkDataChildAttachment()
product1[AdCreativeLinkDataChildAttachment.Field.link] = '<URL>' + '/product1'
product1[AdCreativeLinkDataChildAttachment.Field.name] = 'Product 1'
product1[AdCreativeLinkDataChildAttachment.Field.description] = '$8.99'
product1[AdCreativeLinkDataChildAttachment.Field.image_hash] = '<IMAGE_HASH>'
product1[AdCreativeLinkDataChildAttachment.Field.video_id] = '<VIDEO_ID>'

product2 = AdCreativeLinkDataChildAttachment()
product2[AdCreativeLinkDataChildAttachment.Field.link] = '<URL>' + '/product2'
product2[AdCreativeLinkDataChildAttachment.Field.name] = 'Product 2'
product2[AdCreativeLinkDataChildAttachment.Field.description] = '$9.99'
product2[AdCreativeLinkDataChildAttachment.Field.image_hash] = '<IMAGE_HASH>'

product3 = AdCreativeLinkDataChildAttachment()
product3[AdCreativeLinkDataChildAttachment.Field.link] = '<URL>' + '/product3'
product3[AdCreativeLinkDataChildAttachment.Field.name] = 'Product 3'
product3[AdCreativeLinkDataChildAttachment.Field.description] = '$10.99'
product3[AdCreativeLinkDataChildAttachment.Field.image_hash] = '<IMAGE_HASH>'

link = AdCreativeLinkData()
link[link.Field.link] = '<URL>'
link[link.Field.child_attachments] = [product1, product2, product3]
link[link.Field.caption] = 'My caption'

story = AdCreativeObjectStorySpec()
story[story.Field.page_id] = <PAGE_ID>
story[story.Field.link_data] = link

creative = AdCreative(parent_id='act_<AD_ACCOUNT_ID>')
creative[AdCreative.Field.name] = 'MPA Creative'
creative[AdCreative.Field.object_story_spec] = story
creative.remote_create()
print(creative)
AdCreative adCreative = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdCreative()
  .setName("Sample Creative")
  .setObjectStorySpec(
    new AdCreativeObjectStorySpec()
      .setFieldLinkData(
        new AdCreativeLinkData()
          .setFieldCaption("My caption")
          .setFieldChildAttachments(Arrays.asList(
            new AdCreativeLinkDataChildAttachment()
              .setFieldDescription("$8.99")
              .setFieldImageHash(<IMAGE_HASH>)
              .setFieldLink("https://www.link.com/product1")
              .setFieldName("Product 1")
              .setFieldVideoId(<VIDEO_ID>)
          , 
            new AdCreativeLinkDataChildAttachment()
              .setFieldDescription("$9.99")
              .setFieldImageHash(<IMAGE_HASH>)
              .setFieldLink("https://www.link.com/product2")
              .setFieldName("Product 2")
              .setFieldVideoId(<VIDEO_ID>)
          , 
            new AdCreativeLinkDataChildAttachment()
              .setFieldDescription("$10.99")
              .setFieldImageHash(<IMAGE_HASH>)
              .setFieldLink("https://www.link.com/product3")
              .setFieldName("Product 3")
          ))
          .setFieldLink(<URL>)
      )
      .setFieldPageId(<PAGE_ID>)
  )
  .execute();
String ad_creative_id = adCreative.getId();
curl \
  -F 'name=Sample Creative' \
  -F 'object_story_spec={ 
    "link_data": { 
      "caption": "My caption", 
      "child_attachments": [ 
        { 
          "description": "$8.99", 
          "image_hash": "<IMAGE_HASH>", 
          "link": "https:\/\/www.link.com\/product1", 
          "name": "Product 1", 
          "video_id": "<VIDEO_ID>" 
        }, 
        { 
          "description": "$9.99", 
          "image_hash": "<IMAGE_HASH>", 
          "link": "https:\/\/www.link.com\/product2", 
          "name": "Product 2", 
          "video_id": "<VIDEO_ID>" 
        }, 
        { 
          "description": "$10.99", 
          "image_hash": "<IMAGE_HASH>", 
          "link": "https:\/\/www.link.com\/product3", 
          "name": "Product 3" 
        } 
      ], 
      "link": "<URL>" 
    }, 
    "page_id": "<PAGE_ID>" 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/adcreatives

The response is a creative ID:

{"id":"<CREATIVE_ID>"}

Create Post then Ad

Create an unpublished Page post. child_attachments is an array of link objects. On each link object, picture, name and description are optional. You can post these as by the Page only with a Page access token.

use FacebookAds\Http\RequestInterface;
use FacebookAds\Object\Fields\AdCreativeLinkDataChildAttachmentFields;

$child_attachments = array();

for ($i = 0; $i <= 3; $i++) {
  $child_attachments[] = array(
    AdCreativeLinkDataChildAttachmentFields::LINK => '<LINK>',
    AdCreativeLinkDataChildAttachmentFields::NAME => 'Product '.$i,
    AdCreativeLinkDataChildAttachmentFields::DESCRIPTION => '$4.99',
    AdCreativeLinkDataChildAttachmentFields::IMAGE_HASH => '<IMAGE_HASH_I>',
  );
}

$params = array(
  'message' => 'Browse our latest products',
  'published' => 0,
  'child_attachments' => $child_attachments,
  'caption' => 'WWW.EXAMPLE.COM',
  'link' => 'http://www.example.com/products',
);

$data = Api::instance()->call(
  '/'.<PAGE_ID>.'/feed',
  RequestInterface::METHOD_POST,
  $params)->getContent();
from facebookads import FacebookAdsApi

params = {
    'link': '<URL>',
    'message': 'Browse our latest products',
    'caption': 'My caption',
    'child_attachments': [
        {
            'link': '<URL>' + '/product1',
            'name': 'Product 1',
            'description': '$8.99',
            'image_hash': '<IMAGE_HASH>',
            'video_id': '<VIDEO_ID>',
        },
        {
            'link': '<URL>' + '/product2',
            'name': 'Product 2',
            'description': '$18.99',
            'image_hash': '<IMAGE_HASH>',
            'video_id': '<VIDEO_ID>',
        },
        {
            'link': '<URL>' + '/product3',
            'name': 'Product 3',
            'description': '$28.99',
            'image_hash': '<IMAGE_HASH>',
            'video_id': '<VIDEO_ID>',
        },
    ],
}

data = FacebookAdsApi.get_default_api().\
    call('POST', (<PAGE_ID>, 'feed'), params)
curl \
  -F 'message=Browse our latest products' \
  -F 'published=0' \
  -F 'child_attachments=[ 
    { 
      "link": "<LINK>", 
      "name": "Product 0", 
      "description": "$4.99", 
      "image_hash": "<IMAGE_HASH_I>" 
    }, 
    { 
      "link": "<LINK>", 
      "name": "Product 1", 
      "description": "$4.99", 
      "image_hash": "<IMAGE_HASH_I>" 
    }, 
    { 
      "link": "<LINK>", 
      "name": "Product 2", 
      "description": "$4.99", 
      "image_hash": "<IMAGE_HASH_I>" 
    }, 
    { 
      "link": "<LINK>", 
      "name": "Product 3", 
      "description": "$4.99", 
      "image_hash": "<IMAGE_HASH_I>" 
    } 
  ]' \
  -F 'caption=WWW.EXAMPLE.COM' \
  -F 'link=http://www.example.com/products' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/<PAGE_ID>/feed

Then, provide ad creative with the unpublished Page post. Use the id for the object_story_id in your ad creative.

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Fields\AdCreativeFields;

$creative = new AdCreative(null, 'act_<AD_ACCOUNT_ID>');

$creative->setData(array(
  AdCreativeFields::OBJECT_STORY_ID => <STORY_ID>,
));

$creative->create();
from facebookads.adobjects.adcreative import AdCreative

creative = AdCreative(parent_id='act_<AD_ACCOUNT_ID>')
creative[AdCreative.Field.object_story_id] = <POST_ID>

creative.remote_create()
AdCreative adCreative = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdCreative()
  .setObjectStoryId(object_story_id)
  .execute();
String ad_creative_id = adCreative.getId();
curl \
  -F 'object_story_id=<STORY_ID>' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/adcreatives

Create Video Ad

Video carousel ads can have 'caption' in the child attachment to customize the display URL on the end screen:

"child_attachments": [
 {
   "link": "https://www.facebookmarketingdevelopers.com/",
   "name": "Facebook Marketing Developers",
   "description": "Facebook Marketing Developers",
   "call_to_action": {
     "type": "APPLY_NOW",
     "value": {
      "link_title": "Facebook Marketing Developers"
     }
   },
   "video_id": "123",
   "caption": "mycustomlinkcaption.com"
  },
]

Create Mobile App Ad

Limitations:

  • Carousel mobile app ads support only one app
  • Minimum of 3 images compared to 2 on non-app ad carousel ads
  • Carousel mobile app ads must have a call to action
  • The end card which typically displays the page's profile photo will not display for carousel mobile app ads. Note that you should specify the same app store link in each child_attachment. You do not have to specify the link again in the call_to_action:{'value':{'link':... }}}

Inline

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\Fields\AdCreativeObjectStorySpecFields;
use FacebookAds\Object\Fields\AdCreativeLinkDataFields;
use FacebookAds\Object\Fields\AdCreativeLinkDataChildAttachmentFields;

$child_attachments = array();

for ($i = 0; $i <= 3; $i++) {
  $child_attachments[] = array(
    AdCreativeLinkDataChildAttachmentFields::LINK => '<APP_STORE_URL>',
    AdCreativeLinkDataChildAttachmentFields::IMAGE_HASH => '<IMAGE_HASH>',
    AdCreativeLinkDataChildAttachmentFields::CALL_TO_ACTION => array(
      'type' => 'USE_MOBILE_APP',
      'value' => array(
        'app_link' => '<DEEP_LINK_I>',
        'link_title' => '<LINK_TITLE_I>',
      ),
    ),
  );
}

$object_story_spec = array(
  AdCreativeObjectStorySpecFields::PAGE_ID => <PAGE_ID>,
  AdCreativeObjectStorySpecFields::LINK_DATA => array(
    AdCreativeLinkDataFields::MESSAGE => 'My description',
    AdCreativeLinkDataFields::LINK => '<APP_STORE_URL>',
    AdCreativeLinkDataFields::CAPTION => 'WWW.ITUNES.COM',
    AdCreativeLinkDataFields::CHILD_ATTACHMENTS => $child_attachments,
    AdCreativeLinkDataFields::MULTI_SHARE_OPTIMIZED => true,
  ),
);

$creative = new AdCreative(null, 'act_<AD_ACCOUNT_ID>');
$creative->setData(array(
  AdCreativeFields::NAME => 'Carousel app ad',
  AdCreativeFields::OBJECT_STORY_SPEC => $object_story_spec,
));

$creative->create();
from facebookads.adobjects.adcreative import AdCreative
from facebookads.adobjects.adcreativelinkdata import AdCreativeLinkData
from facebookads.adobjects.adcreativeobjectstoryspec \
    import AdCreativeObjectStorySpec
from facebookads.adobjects.adcreativelinkdatachildattachment \
    import AdCreativeLinkDataChildAttachment

child_attachments = list()
for i in range(3):
    child_attachment = AdCreativeLinkDataChildAttachment()
    child_attachment[AdCreativeLinkDataChildAttachment.Field.link] = \
        '<APP_STORE_URL>'
    child_attachment[AdCreativeLinkDataChildAttachment.Field.image_hash] = \
        '<IMAGE_HASH>'
    child_attachment[
        AdCreativeLinkDataChildAttachment.Field.call_to_action
    ] = {
        'type': 'USE_MOBILE_APP',
        'value': {
            'app_link': '<DEEP_LINK_I>',
            'link_title': '<LINK_TITLE_I>',
        },
    }
    child_attachments.append(child_attachment)

link_data = AdCreativeLinkData()
link_data[AdCreativeLinkData.Field.message] = 'My description'
link_data[AdCreativeLinkData.Field.link] = '<APP_STORE_URL>'
link_data[AdCreativeLinkData.Field.caption] = 'WWW.ITUNES.COM'
link_data[AdCreativeLinkData.Field.child_attachments] = child_attachments
link_data[AdCreativeLinkData.Field.multi_share_optimized] = True

story = AdCreativeObjectStorySpec()
story[story.Field.page_id] = <PAGE_ID>
story[story.Field.link_data] = link_data

creative = AdCreative(parent_id='act_<AD_ACCOUNT_ID>')
creative[AdCreative.Field.name] = 'Carousel app ad'
creative[AdCreative.Field.object_story_spec] = story

creative.remote_create()
AdCreative adCreative = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdCreative()
  .setName("Carousel app ad")
  .setObjectStorySpec(
    new AdCreativeObjectStorySpec()
      .setFieldLinkData(
        new AdCreativeLinkData()
          .setFieldCaption("WWW.ITUNES.COM")
          .setFieldChildAttachments(Arrays.asList(
            new AdCreativeLinkDataChildAttachment()
              .setFieldCallToAction(
                new AdCreativeLinkDataCallToAction()
                  .setFieldType(AdCreativeLinkDataCallToAction.EnumType.VALUE_USE_MOBILE_APP)
                  .setFieldValue(
                    new AdCreativeLinkDataCallToActionValue()
                      .setFieldAppLink(<DEEP_LINK_I>)
                      .setFieldLinkTitle("LINK_TITLE_$i")
                  )
              )
              .setFieldImageHash(<IMAGE_HASH>)
              .setFieldLink(<APP_STORE_URL>)
          , 
            new AdCreativeLinkDataChildAttachment()
              .setFieldCallToAction(
                new AdCreativeLinkDataCallToAction()
                  .setFieldType(AdCreativeLinkDataCallToAction.EnumType.VALUE_USE_MOBILE_APP)
                  .setFieldValue(
                    new AdCreativeLinkDataCallToActionValue()
                      .setFieldAppLink(<DEEP_LINK_I>)
                      .setFieldLinkTitle("LINK_TITLE_$i")
                  )
              )
              .setFieldImageHash(<IMAGE_HASH>)
              .setFieldLink(<APP_STORE_URL>)
          , 
            new AdCreativeLinkDataChildAttachment()
              .setFieldCallToAction(
                new AdCreativeLinkDataCallToAction()
                  .setFieldType(AdCreativeLinkDataCallToAction.EnumType.VALUE_USE_MOBILE_APP)
                  .setFieldValue(
                    new AdCreativeLinkDataCallToActionValue()
                      .setFieldAppLink(<DEEP_LINK_I>)
                      .setFieldLinkTitle("LINK_TITLE_$i")
                  )
              )
              .setFieldImageHash(<IMAGE_HASH>)
              .setFieldLink(<APP_STORE_URL>)
          , 
            new AdCreativeLinkDataChildAttachment()
              .setFieldCallToAction(
                new AdCreativeLinkDataCallToAction()
                  .setFieldType(AdCreativeLinkDataCallToAction.EnumType.VALUE_USE_MOBILE_APP)
                  .setFieldValue(
                    new AdCreativeLinkDataCallToActionValue()
                      .setFieldAppLink(<DEEP_LINK_I>)
                      .setFieldLinkTitle("LINK_TITLE_$i")
                  )
              )
              .setFieldImageHash(<IMAGE_HASH>)
              .setFieldLink(<APP_STORE_URL>)
          ))
          .setFieldLink(<APP_STORE_URL>)
          .setFieldMessage("My description")
          .setFieldMultiShareOptimized(true)
      )
      .setFieldPageId(<PAGE_ID>)
  )
  .execute();
String ad_creative_id = adCreative.getId();
curl \
  -F 'name=Carousel app ad' \
  -F 'object_story_spec={ 
    "page_id": "<PAGE_ID>", 
    "link_data": { 
      "message": "My description", 
      "link": "<APP_STORE_URL>", 
      "caption": "WWW.ITUNES.COM", 
      "child_attachments": [ 
        { 
          "link": "<APP_STORE_URL>", 
          "image_hash": "<IMAGE_HASH>", 
          "call_to_action": { 
            "type": "USE_MOBILE_APP", 
            "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
          } 
        }, 
        { 
          "link": "<APP_STORE_URL>", 
          "image_hash": "<IMAGE_HASH>", 
          "call_to_action": { 
            "type": "USE_MOBILE_APP", 
            "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
          } 
        }, 
        { 
          "link": "<APP_STORE_URL>", 
          "image_hash": "<IMAGE_HASH>", 
          "call_to_action": { 
            "type": "USE_MOBILE_APP", 
            "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
          } 
        }, 
        { 
          "link": "<APP_STORE_URL>", 
          "image_hash": "<IMAGE_HASH>", 
          "call_to_action": { 
            "type": "USE_MOBILE_APP", 
            "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
          } 
        } 
      ], 
      "multi_share_optimized": true 
    } 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/adcreatives

Post Then Ad

Posts can only be posted as by the Page using a Page access token.

$child_attachments = array();

for ($i = 0; $i <= 3; $i++) {
  $child_attachments[] = array(
    'link' => '<APP_STORE_URL>',
    'image_hash' => '<IMAGE_HASH_I>',
    'call_to_action' => array(
      'type' => 'USE_MOBILE_APP',
      'value' => array(
        'app_link' => '<DEEP_LINK_I>',
        'link_title' => '<LINK_TITLE_I>',
      ),
    ),
  );
}

$params = array(
  'message' => 'My description',
  'link' => '<APP_STORE_URL>',
  'caption' => 'WWW.ITUNES.COM',
  'child_attachments' => $child_attachments,
  'multi_share_optimized' => true,
);

$data = Api::instance()->call(
  '/'.'<PAGE_ID>'.'/feed',
  RequestInterface::METHOD_POST,
  $params)->getContent();
from facebookads import FacebookAdsApi
from facebookads.adobjects.adcreativelinkdatachildattachment \
    import AdCreativeLinkDataChildAttachment

child_attachments = list()

for i in range(3):
    child_attachments.append({
        AdCreativeLinkDataChildAttachment.Field.link: '<APP_STORE_URL>',
        AdCreativeLinkDataChildAttachment.Field.image_hash: '<IMAGE_HASH>',
        AdCreativeLinkDataChildAttachment.Field.call_to_action: {
            'type': 'USE_MOBILE_APP',
            'value': {
                'app_link': '<DEEP_LINK_I>',
                'link_title': '<LINK_TITLE_I>',
            },
        },
    })

params = {
    'message': 'My description',
    'link': '<APP_STORE_URL>',
    'caption': 'WWW.ITUNES.COM',
    'child_attachments': child_attachments,
    'multi_share_optimized': True,
}

data = FacebookAdsApi.get_default_api().\
    call('POST', (<PAGE_ID>, 'feed'), params)
curl \
  -F 'message=My description' \
  -F 'link=<APP_STORE_URL>' \
  -F 'caption=WWW.ITUNES.COM' \
  -F 'child_attachments=[ 
    { 
      "link": "<APP_STORE_URL>", 
      "image_hash": "<IMAGE_HASH_I>", 
      "call_to_action": { 
        "type": "USE_MOBILE_APP", 
        "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
      } 
    }, 
    { 
      "link": "<APP_STORE_URL>", 
      "image_hash": "<IMAGE_HASH_I>", 
      "call_to_action": { 
        "type": "USE_MOBILE_APP", 
        "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
      } 
    }, 
    { 
      "link": "<APP_STORE_URL>", 
      "image_hash": "<IMAGE_HASH_I>", 
      "call_to_action": { 
        "type": "USE_MOBILE_APP", 
        "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
      } 
    }, 
    { 
      "link": "<APP_STORE_URL>", 
      "image_hash": "<IMAGE_HASH_I>", 
      "call_to_action": { 
        "type": "USE_MOBILE_APP", 
        "value": {"app_link":"<DEEP_LINK_I>","link_title":"<LINK_TITLE_I>"} 
      } 
    } 
  ]' \
  -F 'multi_share_optimized=1' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/<PAGE_ID>/feed

Use the id from the response to create the AdCreative:

use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Fields\AdCreativeFields;

$creative = new AdCreative(null, 'act_<AD_ACCOUNT_ID>');

$creative->setData(array(
  AdCreativeFields::OBJECT_STORY_ID => <STORY_ID>,
));

$creative->create();
from facebookads.adobjects.adcreative import AdCreative

creative = AdCreative(parent_id='act_<AD_ACCOUNT_ID>')
creative[AdCreative.Field.object_story_id] = <POST_ID>

creative.remote_create()
AdCreative adCreative = new AdAccount(act_<AD_ACCOUNT_ID>, context).createAdCreative()
  .setObjectStoryId(object_story_id)
  .execute();
String ad_creative_id = adCreative.getId();
curl \
  -F 'object_story_id=<STORY_ID>' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/adcreatives

Field Specification

This is a Carousel Ad on iOS, showing how fields described are used.

NameTypeDescription

child_attachments

object

A 2-5 element array of link objects required for carousel ads. If multi_share_optimized is true, this array can have up to 10 objects. You should use at least 3 objects for optimal performance; 2 objects is for enabling lightweight integrations and using 2 objects can result in sub-optimal campaign results.

link

string

Link URL or app store URL attached to the post. Required.

picture

URL

Preview image associated with the link. 1:1 aspect ratio and a minimum of 458 x 458 px for best display. Either picture or image_hash must be specified.

image_hash

string

Hash of preview image associated with the link from your image library 1:1 aspect ratio and a minimum of 458 x 458 px for best display. Either picture or image_hash must be specified.

name

string

Title of link preview. If not specified, title of the linked page used. Typically truncated after 35 characters. You should set a unique name, since Facebook interfaces show actions reported by name.

description

string

Either a price, discount or website domain. If not specified, content from the linked page is extracted and used. Typically truncated after 30 characters.

call_to_action

object

Optional call to action. See Call To Action. You do not have to specify the link again in call_to_action:{'value':{'link':... }}}

video_id

string

ID of the ad video. Can be used in any child-element. If specified, must also set image_hash or picture.

message

string

Main body of post, also called the status message.

link

string

URL of a link to "See more". Required.

caption

string

URL to display in the "See more" link. Not applicable for carousel mobile app ads

multi_share_optimized

boolean

If set to true, automatically select and order images and links. Otherwise use original order of child elements. Defaults to true.

multi_share_end_card

boolean

If set to false, removes the end card which displays the page icon. Default is true.

Per-Product Ad Statistics

Carousel breakdown metrics for action_report_time=impression are inaccurate before June 20th, 2015 (6/20/2015). Carousel breakdown metrics for action_report_time=conversion are inaccurate before July 20th, 2015 (7/20/2015).

Group actions for Carousel ads by each product with actions_breakdown=['action_carousel_card_id', 'action_carousel_card_name']. Each child_attachment has a different card ID. action_carousel_card_id and action_carousel_card_name is only for Carousel ads.

Get the following stats per card:

  • website_ctr: available when specifying fields=['website_ctr']
  • app_install, app_use, apps.uses, credit_spent, mobile_app_install, tab_view, link_click, mobile_app_install, app_custom_event.*, offsite_conversion.*: available when specifying fields=['actions']. Other actions are not available with a card breakdown.
use FacebookAds\Object\AdAccount;
use FacebookAds\Object\Fields\AdsInsightsFields;
use FacebookAds\Object\Values\AdsInsightsActionBreakdownsValues;
use FacebookAds\Object\Values\AdsInsightsBreakdownsValues;
use FacebookAds\Object\Values\AdsInsightsLevelValues;
use FacebookAds\Object\Values\AdsInsightsDatePresetValues;
use FacebookAds\Object\Values\InsightsIncrements;
use FacebookAds\Object\Values\InsightsOperators;

$account = new AdAccount('act_<AD_ACCOUNT_ID>');

$params = array(
  'action_breakdowns' => array(
    AdsInsightsActionBreakdownsValues::ACTION_TYPE,
    AdsInsightsActionBreakdownsValues::ACTION_CAROUSEL_CARD_ID,
  ),
  'level' => AdsInsightsLevelValues::AD,
  'date_preset' => AdsInsightsDatePresetValues::LAST_30_DAYS,
  'time_increment' => InsightsIncrements::ALL_DAYS,
  'breakdowns' => AdsInsightsBreakdownsValues::PLACEMENT,
  'filtering' => array(
    array(
      'field' => 'action_type',
      'operator' => InsightsOperators::IN,
      'value' => array('link_click'),
    ),
  ),
);

$fields = array(
  AdsInsightsFields::IMPRESSIONS,
  AdsInsightsFields::INLINE_LINK_CLICKS,
  AdsInsightsFields::ACTIONS,
  AdsInsightsFields::WEBSITE_CTR,
);

$stats = $account->getInsights($fields, $params);
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.adsinsights import AdsInsights


account = AdAccount('act_<AD_ACCOUNT_ID>')

params = {
    'action_breakdowns': [
        AdsInsights.ActionBreakdowns.action_type,
        AdsInsights.ActionBreakdowns.action_carousel_card_id,
    ],
    'fields': [
        AdsInsights.Field.impressions,
        AdsInsights.Field.unique_clicks,
        AdsInsights.Field.actions,
        AdsInsights.Field.website_ctr,
    ],
    'level': AdsInsights.Level.ad,
    'date_preset': AdsInsights.DatePreset.last_30_days,
    'time_increment': 'all_days',
    'breakdowns': AdsInsights.Breakdowns.placement,
    'filtering': [{
        'field': 'action_type',
        'operator': 'IN',
        'value': ['link_click']
    }]
}

stats = account.get_insights(params=params)
print(stats)
APINodeList<AdsInsights> adsInsightss = new AdAccount(act_<AD_ACCOUNT_ID>, context).getInsights()
  .setActionBreakdowns("[\"action_type\",\"action_carousel_card_id\"]")
  .setLevel(AdsInsights.EnumLevel.VALUE_AD)
  .setDatePreset(AdsInsights.EnumDatePreset.VALUE_LAST_30_DAYS)
  .setTimeIncrement("all_days")
  .setBreakdowns("placement")
  .setFiltering("[{\"field\":\"action_type\",\"operator\":\"IN\",\"value\":[\"link_click\"]}]")
  .requestField("impressions")
  .requestField("inline_link_clicks")
  .requestField("actions")
  .requestField("website_ctr")
  .execute();
curl -G \
  -d 'action_breakdowns=["action_type","action_carousel_card_id"]' \
  -d 'level=ad' \
  -d 'date_preset=last_30_days' \
  -d 'time_increment=all_days' \
  -d 'breakdowns=placement' \
  --data-urlencode 'filtering=[ 
    { 
      "field": "action_type", 
      "operator": "IN", 
      "value": ["link_click"] 
    } 
  ]' \
  -d 'fields=impressions,inline_link_clicks,actions,website_ctr' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/insights

Response:

{
...
   "website_ctr": [
      {
         "action_carousel_card_id": "1",
         "action_type": "link_click",
         "value": 51.401869158878
      },
      {
         "action_carousel_card_id": "2",
         "action_type": "link_click",
         "value": 50.980392156863
      }
   ],
   "placement": "mobile_feed",
   "date_start": "2015-05-25",
   "date_stop": "2015-05-28"
}

You can also request cost_per_action_type for a breakdown of costs by action type:

use FacebookAds\Object\AdAccount;
use FacebookAds\Object\Fields\AdsInsightsFields;
use FacebookAds\Object\Values\AdsInsightsActionBreakdownsValues;
use FacebookAds\Object\Values\AdsInsightsBreakdownsValues;
use FacebookAds\Object\Values\AdsInsightsLevelValues;

$account = new AdAccount('act_<AD_ACCOUNT_ID>');

$params = array(
  'action_breakdowns' => array(
    AdsInsightsActionBreakdownsValues::ACTION_TYPE,
    AdsInsightsActionBreakdownsValues::ACTION_CAROUSEL_CARD_NAME,
  ),
  'level' => AdsInsightsLevelValues::AD,
  'breakdowns' => AdsInsightsBreakdownsValues::PLACEMENT,
);

$fields = array(
  AdsInsightsFields::IMPRESSIONS,
  AdsInsightsFields::CAMPAIGN_NAME,
  AdsInsightsFields::COST_PER_ACTION_TYPE,
);

$stats = $account->getInsights($fields, $params);
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.adsinsights import AdsInsights

account = AdAccount('act_<AD_ACCOUNT_ID>')

params = {
    'action_breakdowns': [
        AdsInsights.ActionBreakdowns.action_type,
        AdsInsights.ActionBreakdowns.action_carousel_card_name,
    ],
    'fields': [
        AdsInsights.Field.impressions,
        AdsInsights.Field.campaign_name,
        AdsInsights.Field.cost_per_action_type,
    ],
    'level': AdsInsights.Level.ad,
}

stats = account.get_insights(params=params)
print(stats)
APINodeList<AdsInsights> adsInsightss = new AdAccount(act_<AD_ACCOUNT_ID>, context).getInsights()
  .setActionBreakdowns("[\"action_type\",\"action_carousel_card_name\"]")
  .setLevel(AdsInsights.EnumLevel.VALUE_AD)
  .setBreakdowns("placement")
  .requestField("impressions")
  .requestField("campaign_name")
  .requestField("cost_per_action_type")
  .execute();
curl -G \
  -d 'action_breakdowns=["action_type","action_carousel_card_name"]' \
  -d 'level=ad' \
  -d 'breakdowns=placement' \
  -d 'fields=impressions,campaign_name,cost_per_action_type' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.8/act_<AD_ACCOUNT_ID>/insights

Sample response:

{
   "data": [
      {
         "impressions": "1862555",
         "campaign_name": "My Campaign",
         "cost_per_action_type": [
            {
               "action_carousel_card_name": "My Carousel Card 1",
               "action_type": "app_custom_event.fb_mobile_activate_app",
               "value": 0.093347346315861
            },
            {
               "action_carousel_card_name": "My Carousel Card 2",
               "action_type": "app_custom_event.fb_mobile_activate_app",
               "value": 0.38324089579301
            },
            ...
         ],
      }
   ]
}

Resources