Storing and Retrieving Ad Objects

Ad Campaign, Ad Set and Ads have one of following status types:

  • Live
  • Archived
  • Deleted

For background see Ads Developer Blog, Deleted versus Archived.

Live

Live ad objects can have the following status:

  • ACTIVE
  • PAUSED, for ADSET or CAMPAIGN
  • PENDING_REVIEW
  • CREDIT_CARD_NEEDED
  • PREAPPROVED
  • DISABLED

Archived

Set the ad object to ARCHIVED by setting status field to ARCHIVED. When an object status is set to ARCHIVED you can continue to query the details and stats based on the object id. However there is maximum limit on the number of objects you can archive. So you should respect this limit and change status to DELETED when you no longer need an object.

An ARCHIVED object has only two fields you can change: name and status. You can also only change status to DELETED.

Deleted

Set the ad object to DELETED by either setting status field to DELETED or sending an HTTP DELETE to that object. Once an object status is set to DELETED you cannot set it back to ARCHIVED.

If you keep the deleted object ID, you can continue to retrieve stats or object details by querying the object ID. However you cannot retrieve the deleted objects as a connection object from a non deleted node or object. For example, <API_VERSION>/<AD_ID>/insights works for a deleted object but <API_VERSION>/act_<AD_ACCOUNT_ID>/insights?level=ad does not return stats for the deleted object.

After you delete an ad, it may still track impressions, clicks, and actions for 28 days after the date of last delivery. You can query insights for DELETED objects using the ad.effective_status filter.

If you have an ad set with two adsin it, and you delete one ad, the following two queries do not return the same results:

https://graph.facebook.com/&lt;API_VERSION>/<AD_SET_ID>/insights
https://graph.facebook.com/&lt;API_VERSION>/<AD_ID>/insights

The ad set returns stats for both the deleted and the non-deleted ads in it. However when you query for ads in the ad set, you only see one ad:

https://graph.facebook.com/<API_VERSION>/<AD_SET_ID>/ads

To avoid this scenario, you should delete ads 28 days after their last date of delivery to ensure stats no longer change. Also you should store the stats or ids of those objects in your own system before you delete them. This recommendation is optional:

  • If your application does not show the breakdown of stats, or
  • You do not care if the sum of breakdowns of stats do not match that of the parent object, due to some deleted child objects.

You cannot change any field, except name, for a DELETED object.

Managing Status

This is how you typically manage object status:

  • You create ad objects, they run and start delivering
  • When you delete an object, we automatically delete it
  • When you reach the limit for achived objects, you can no longer archive more objects.
  • You should move archived deleted objects to the deleted state to reduce the limit.

The status on ad objects works this way for the hierarchy of ad objects:

  • If you set the status to paused, archived, or deleted for a campaign, all the objects below it will automatically inherit that status. If you set an ad campaign to deleted, you cannot retrieve the ad sets or ads below that campaign without explicitly specifying the IDs.
  • If you set the ad status to paused, archived, or deleted, the ad set or ad campaign containing that ad will keep its original status and will be available for retrieval.

The following limits apply to ARCHIVED objects for given ad account:

  • 100,000 for Ad Campaigns
  • 100,000 for Ad Sets
  • 100,000 for Ads

If you read archived edges, you need to specifically filter for the archived objects since we do not return them by default. If you read stats for an ad object, we include the stats of all children objects, no matter if the child is active, archived, or deleted. Therefore you need no filter for insights on child objects.

Comparisons Different Statuses

Objects with statuses such as ACTIVE, PAUSED differ from those with ARCHIVED status, and DELETED. Here are the major differences.

Query Live `ARCHIVED` `DELETED`

Exists in database

Yes

Yes

Yes

Maximum number per ad account

With limits

50,000

No limit

Query as edges without filter

Yes

No

No

Query as edges with status filter

Yes for objects of status contained in the filter

Yes if status filter contains ARCHIVED.

No if status filter does not contain DELETED, and error if it does.

Query by its own ID

Yes

Yes

Yes

Stats aggregated in /<PARENT_OBJECT_ID>/insights

Yes

Yes

Yes

Stats included in the result list of /<PARENT_OBJECT_ID>/insights?level=<OBJECT_LEVEL>

Yes

No

No

Stats included in the result list of /<PARENT_OBJECT_ID>/insights with delivery_info filtering

Yes for objects of status contained in the filter

Yes for objects of status contained in the filter

No

Insights shown with /<OBJECT_ID>/insights

Yes

Yes

Yes

Status can be changed to

Any valid status

DELETED

Cannot change

To set an ad to be archived:

use FacebookAds\Object\Ad;

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

ad = Ad(ad_id)
ad.remote_archive()
new Ad(<AD_ID>, context).update()
  .setStatus(Ad.EnumStatus.VALUE_ARCHIVED)
  .execute();
curl \
  -F 'status=ARCHIVED' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<AD_ID>

To delete an ad:

use FacebookAds\Object\Ad;

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

ad = Ad(<AD_ID>)
ad.remote_delete()
new Ad(<AD_ID>, context).update()
  .setStatus(Ad.EnumStatus.VALUE_DELETED)
  .execute();
curl -X DELETE \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<AD_ID>/

To retrieve live sub-objects of a live object, for example, all live ads of an ad campaign, not including ARCHIVED or DELETED ads:

curl -X GET \ -d 'fields=name' \ -d 'access_token=<ACCESS_TOKEN>' \ https://graph.facebook.com/v3.1/<AD_CAMPAIGN_ID>/ads
const adsSdk = require('facebook-nodejs-ads-sdk'); const Campaign = adsSdk.Campaign; const Ad = adsSdk.Ad; let access_token = '<ACCESS_TOKEN>'; let app_secret = '<APP_SECRET>'; let app_id = '<APP_ID>'; let id = '<ID>'; const api = adsSdk.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 = [ 'name', ]; params = { }; let adss = (new Campaign(id)).getAds( fields, params ); logApiCallResult('adss api call complete.', adss);
require __DIR__ . '/vendor/autoload.php'; use FacebookAds\Object\Campaign; use FacebookAds\Object\Ad; use FacebookAds\Api; use FacebookAds\Logger\CurlLogger; $access_token = '<ACCESS_TOKEN>'; $app_secret = '<APP_SECRET>'; $app_id = '<APP_ID>'; $id = '<ID>'; $api = Api::init($app_id, $app_secret, $access_token); $api->setLogger(new CurlLogger()); $fields = array( 'name', ); $params = array( ); echo json_encode((new Campaign($id))->getAds( $fields, $params )->getResponse()->getContent(), JSON_PRETTY_PRINT);
from facebookads.adobjects.campaign import Campaign from facebookads.adobjects.ad import Ad from facebookads.api import FacebookAdsApi access_token = '<ACCESS_TOKEN>' app_secret = '<APP_SECRET>' app_id = '<APP_ID>' id = '<ID>' FacebookAdsApi.init(access_token=access_token) fields = [ 'name', ] params = { } print Campaign(id).get_ads( 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 = \"<ID>\"; APIContext context = new APIContext(access_token).enableDebug(true); new Campaign(id, context).getAds() .requestNameField() .execute(); } }
require 'facebook_ads' access_token = '<ACCESS_TOKEN>' app_secret = '<APP_SECRET>' app_id = '<APP_ID>' id = '<ID>' FacebookAds.configure do |config| config.access_token = access_token config.app_secret = app_secret end campaign = FacebookAds::Campaign.get(id) adss = campaign.ads({ fields: { 'name' }, })

To retrieve ARCHIVED sub-objects of a live object, for example, all ARCHIVED ads of an ad set, requires the status filter:

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

$campaign = new Campaign(<CAMPAIGN_ID>);
$params = array(
  AdFields::EFFECTIVE_STATUS => array(
    Ad::STATUS_ARCHIVED,
  ),
);
$ads = $campaign->getAds(
  array(AdFields::NAME),
  $params);

foreach ($ads as $ad) {
  echo $ad->{AdFields::NAME}.PHP_EOL;
}
from facebookads.adobjects.campaign import Campaign
from facebookads.adobjects.ad import Ad

campaign = Campaign(<CAMPAIGN_ID>)
params = {
    Ad.Field.effective_status: [Ad.Status.archived],
}
ads = campaign.get_ads(
    fields=[Ad.Field.name],
    params=params,
)

for ad in ads:
    print(ad[Ad.Field.name])
APINodeList<Ad> ads = new Campaign(<CAMPAIGN_ID>, context).getAds()
  .setEffectiveStatus("[\"ARCHIVED\"]")
  .requestNameField()
  .execute();
curl -G \
  -d 'effective_status=["ARCHIVED"]' \
  -d 'fields=name' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<CAMPAIGN_ID>/ads