def estimate( self, account_id, product_set_id, targeting_spec, ): """ This function will estimate product audience of `product_set_id`, defined with `targeting_spec`, in the context of ad account `account_id`. You need to ensure that ad account and product set are belong to same business, otherwise probably we will get invalid response or zero audience from Facebook. Params: * `account_id`: The ad account id to use in estimation, in format of `act_xxxxxx`. * `product_set_id`: The product set id to use in estimation. * `targeting_spec`: The product audience targeting spec without `product_set_id` as we will set it in code. Please check here for how to define product audience rules (https://developers.facebook.com/docs/marketing-api/dynamic-product-ads/product-audiences, step 3). """ adaccount = AdAccount(account_id) ts = copy.deepcopy(targeting_spec) ts['product_set_id'] = product_set_id targeting_spec = {'product_audience_specs': [ts]} params = { 'currency': 'USD', 'optimize_for': ReachEstimate.OptimizeFor.link_clicks, 'targeting_spec': targeting_spec, } reachestimates = adaccount.get_reach_estimate(params=params) return reachestimates.get_one()
def get_ad_sets(self, account_id, include_archived, limit): """ Retrieves and displays a list of ad sets of a given account, and analyze how likely a similar ad for Instagram can be created. Params: * `account_id` is your Facebook Ad Account id. * `include_archived` specifies whether archived ad sets should be analyzed. * `limit` is how many ad sets to analyze. This script will analyze the first `limit` ad sets as in the response, not including those which use Instagram placement already. The more this limit is, the longer it takes to run. If you run the script directly and are willing to wait for a while, you can drop the lines of code around it. For more information see the [Instagram Ads document]( https://developers.facebook.com/docs/marketing-api/guides/instagramads/) """ locale.setlocale(locale.LC_ALL, '') if include_archived: params = { 'limit': limit, AdSet.Field.configured_status: [ 'PENDING', 'ACTIVE', 'PAUSED', 'PENDING_REVIEW', 'DISAPPROVED', 'PREAPPROVED', 'PENDING_BILLING_INFO', 'CAMPAIGN_PAUSED', 'CAMPAIGN_GROUP_PAUSED', 'ARCHIVED' ], } else: params = {'limit': limit} account = AdAccount(account_id) ad_sets = account.get_ad_sets(fields=[ AdSet.Field.id, AdSet.Field.campaign_id, AdSet.Field.name, AdSet.Field.configured_status, AdSet.Field.targeting, ], params=params) cache = {} count = 0 results = [] for ad_set in ad_sets: if count >= limit: break count += 1 result = {} result['id'] = ad_set['id'] result['name'] = ad_set['name'] logger.error(ad_set) # Get targeting from ad set targeting = ad_set.get(AdSet.Field.targeting, None) logger.error(targeting) if targeting is not None: publisher_platforms = targeting.get('publisher_platforms', None) pp_str = '' if publisher_platforms is None: result['publisher_platforms'] = '<li>DEFAULT</li>' else: for pp in publisher_platforms: pp_str += ('<li>' + self.translate_placement_publisher( str(pp)) + '</li>') result['publisher_platforms'] = pp_str params = { 'currency': 'USD', 'targeting_spec': targeting, 'optimize_for': AdSet.OptimizationGoal.impressions, } if publisher_platforms is not None and "instagram" in \ publisher_platforms: count -= 1 continue reach_fb = account.get_reach_estimate(params=params)[0].get( 'users', 0) targeting['publisher_platforms'] = ["instagram"] targeting['facebook_positions'] = None params = { 'currency': 'USD', 'targeting_spec': targeting, 'optimize_for': AdSet.OptimizationGoal.impressions, } reach_ig = account.get_reach_estimate(params=params)[0].get( 'users', 0) self.add_check_result(result, self.check_audience(reach_fb, reach_ig)) result["audience"] = reach_ig * 100 / reach_fb result["ig_audience"] = locale.format("%d", reach_ig, grouping=True) # Get objective and status from Campaign campaign_id = ad_set[AdSet.Field.campaign_id] campaign = self.get_ad_campaign(cache, campaign_id) result["c_objective"] = \ campaign[Campaign.Field.objective].replace("_", " ") result["c_status"] = campaign[Campaign.Field.configured_status] check = self.check_objective(result["c_objective"]) if check['eligibility'] == 5: result['objective_supported'] = 1 elif check['eligibility'] == 1: result['objective_supported'] = 0 else: result['objective_supported'] = 2 self.add_check_result(result, check) # Get creative and check the media if campaign[Campaign.Field.objective] == 'PRODUCT_CATALOG_SALES': result['preview_url'] = \ 'Images from product catalog are not supported.' results.append(result) result['creative_ready'] = False continue creatives = ad_set.get_ad_creatives([ AdCreative.Field.object_story_id, ]) result['creative_ready'] = False if not creatives: comment = 'No creative found in this ad set.' self.add_check_result(result, { "eligibility": 3, }) result['preview_url'] = comment results.append(result) continue creative = creatives[0] story_id = creative.get(AdCreative.Field.object_story_id, 0) if story_id == 0: comment = 'No post fround in the first creative of this ad set.' self.add_check_result(result, { "eligibility": 3, }) result['preview_url'] = comment results.append(result) continue # Check whether the creative's post is IG ready try: # This Graph API call is not a part of Ads API thus no SDK post = FacebookAdsApi.get_default_api().call( 'GET', (story_id, ), params={ 'fields': 'is_instagram_eligible,child_attachments' }, ) post_ig_eligible = post.json()['is_instagram_eligible'] except FacebookRequestError: post_ig_eligible = False result['creative_ready'] = post_ig_eligible if post_ig_eligible: self.add_check_result(result, { "eligibility": 5, }) # Generate preview # As we do not know which IG account you will use, # just use a hardcoded one for preview. jasper_ig_account = "1023317097692584" ad_format = 'INSTAGRAM_STANDARD' creative_spec = { 'instagram_actor_id': jasper_ig_account, 'object_story_id': story_id, } params = { AdPreview.Field.creative: creative_spec, AdPreview.Field.ad_format: ad_format, } preview = account.get_generate_previews(params=params) result['preview_url'] = preview[0].get_html() \ .replace('width="320"', 'width="340"', 1) else: comment = 'The creative needs to be modified for Instagram.' self.add_check_result(result, { "eligibility": 3, }) result['preview_url'] = comment results.append(result) return list( sorted(results, key=lambda result: result['eligibility'], reverse=True))
# Policies [http://developers.facebook.com/policy/]. This copyright notice # shall be included in all copies or substantial portions of the software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from facebookads import test_config ad_account_id = test_config.account_id # _DOC oncall [duliomatos] # _DOC open [ADACCOUNT_GET_REACHESTIMATE] # _DOC vars [ad_account_id:s] from facebookads.objects import AdAccount, AdSet account = AdAccount(ad_account_id) targeting_spec = {"geo_locations": {"countries": ["US"]}, "age_min": 20, "age_max": 40} params = { "currency": "USD", "optimize_for": AdSet.OptimizationGoal.offsite_conversions, "targeting_spec": targeting_spec, } reach_estimate = account.get_reach_estimate(params=params) print(reach_estimate) # _DOC close [ADACCOUNT_GET_REACHESTIMATE]