Placements

Available for Facebook desktop and mobile (Feed, Stories, Marketplace) and Instagram (Feed, Stories, Reels, Profile Feed, Explore Home, Profile Reels).

Delivery Optimization

  • Reach Optimization — Available to all advertisers with access to this API. It optimizes for daily unique reach and shows "Impressions" as the default metric in Ads Manager reporting.

Create Advantage+ Catalog Ads

To create Advantage+ catalog ads for this objective, your page must use Facebook Locations.

Requirements

  • Campaigns must have objective set to STORE_VISITS.
  • Campaigns must have promoted_object set to the corresponding <PARENT_PAGE_ID>.
  • Ad set promoted_object and targeting must contain a place_page_set_id of a <PAGE_SET_ID>
  • Ad set optimization_goal must be set to REACH
  • Ad set billing_event should be IMPRESSIONS

Step 1. Create a PageSet

Facebook uses PageSet to target ads and uses it as the promoted object in your ad.

To create a PageSet:

  1. Collect store locations, which are Facebook pages for each store location and locations for your primary business. Your primary business is known as a main page.
  2. Create a Locations JSON structure to represent all of your locations.
  3. Create the PageSet with the Locations JSON structure.

Collect all store locations

The <PARENT_PAGE_ID> is the page ID for the main page for all your store locations. It retrieves all store pages and locations that belong to the main page and returns the longitude and latitude for each location:

curl -X GET \
  -d 'fields="location{latitude,longitude},is_permanently_closed"' \
  -d 'limit=30000' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<API_VERSION>/<PARENT_PAGE_ID>/locations

Example output

{
    "data": [
        {
            "location": {
                "latitude": 29.173384,
                "longitude": 48.098807
            },
            "is_permanently_closed": false,
            "id": "1788030244802584"
        },
        {
            "location": {
                "latitude": 29.303635,
                "longitude": 47.937725
            },
            "is_permanently_closed": false,
            "id": "261533444245300"
        },
        {
            "location": {
                "latitude": 29.302303,
                "longitude": 47.933178
            },
            "is_permanently_closed": false,
            "id": "179435399132774"
        },
        {
            "location": {
                "latitude": 29.302591,
                "longitude": 47.931801
            },
            "is_permanently_closed": false,
            "id": "1790317704582144"
        }
    ],
    "paging": {
        "cursors": {
            "before": "MTc4ODAzMDI0NDgwMjU4NAZDZD",
            "after": "MTA4MTU4NjU5NjA5MDA4"
        }
    }
}

Create a Locations JSON structure

Iterate through each entry in the returned results and verify each location is open for business by checking the is_permanently_closed field.

Get the estimated radius using two GET requests to obtain the radius and distance_unit parameters. Alternatively, you can make a batch API call to generate the values below.

Individual Requests

You should make this request using each store page's latitude and longitude from the JSON results returned from the main page. This returns the estimated radius for each location.

curl -X GET \
  -d 'type="adradiussuggestion"' \
  -d 'latitude=51.5152253' \
  -d 'longitude=-0.1423029' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v20.0/search/

Batch Requests

You can also batch multiple requests into a single request.

curl \
  -F "access_token=<ACCESS_TOKEN>" \
  -F "include_headers=false" \
  -F "batch=[
    {
      \"method\": \"GET\",
      \"relative_url\": \"/<API_VERSION>/search?type=adradiussuggestion&amp;latitude=29.173384&amp;longitude=48.098807\"
    },
    {
      \"method\": \"GET\",
      \"relative_url\": \"/<API_VERSION>/search?type=adradiussuggestion&amp;latitude=29.303635&amp;longitude=47.937725\"
    }
  ]" \
  "https://graph.facebook.com"
Final Locations JSON structure

Use the radius and distance_unit parameters obtained from the previous calls along with each location's <CHILD_LOCATION_ID> as the page_id to create the final Locations JSON structure.

[
    {
      "page_id": 1788030244802584,
      "radius": 1,
      "distance_unit": "mile"
    },
    {
      "page_id": 261533444245300,
      "radius": 1,
      "distance_unit": "mile"
    }
]

Create the Pageset with the Locations JSON structure

The PageSet endpoint is currently only available to Partners on the allow list. Please contact your Facebook representative for access.

You can now create a PageSet with the information in your Locations JSON structure.

The maximum number of locations that can be used in a PageSet is 10,000.

Asynchronous Requests

You can make an asynchronous request to create your PageSet. This enables you to create large PageSets with more than 1,000 locations without experiencing timeouts. We recommend you use asynchronous requests whenever you create a Pageset with over 50 locations.

Request

curl -X POST \
  -d 'name=<AD_SET_NAME>' \
  -d 'parent_page=<PARENT_PAGE_ID>' \
  -d 'pages=[{"page_id":<CHILD_PAGE_ID>}]' \
  -d 'metadata={"audience":{"size":<AUDIENCE_SIZE>}}' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/ad_place_page_sets_async/

Note: You can use /ad_place_page_sets for synchronous requests; however, you should use asynchronous requests for more than 50 locations.

The format for parameters are the same as those you use for synchronous requests.

Inside your PageSet, you can use the metadata field to specify a fixed radius per location for your ads delivery or to reach a certain audience size. If you select the latter, Facebook automatically calculates a radius per location to reach that number of Accounts Center accounts.

In this example, the metadata field is set to a desired audience size. See metadata for Radiuses. This returns an ad_place_page_set_async_request ID.

{
  "id": "405738580111111"
}      

Later, you can query that ID with the ads_read permission to get the PageSet ID.

curl -i -X GET \
 "https://graph.facebook.com/<API_VERSION>/405738580111111?access_token=ACCESS_TOKEN"

Example Output

{
  "id": "405738580111111", 
  "place_page_set": {
    "id": "555555791481678",
    "name": "test_ad_set"
  },
  "progress": 1
}

Where progress is from 0.0 to 1, and 1 means we completed your request and created a PageSet.

Using metadata for radiuses

The metadata field tells Facebook you want to use a fixed radius for your locations or you want Facebook to automatically calculate radiuses per location based on a given audience size.

Request

To specify a fixed radius using a synchronous request:

curl -X POST \
  -d 'name=<PAGE_SET_NAME>' \
  -d 'parent_page=<PARENT_PAGE_ID>' \
  -d 'pages=[{"page_id":<CHILD_PAGE_ID>}]' \
  -d 'metadata={"fixed_radius":{"value":5,"distance_unit":"mile"}}' \
  -d 'access_token=ACCESS_TOKEN' \
  https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/ad_place_page_sets/

This means you want Facebook to deliver your ad to people within a 5-mile radius of all locations in your PageSet.

Example Output

{
  "id": "1618547271777777"
}

Note: The metadata field should be set to either fixed_radius or audience.

If you use fixed_radius, you need to provide distance_unit and value:

{
  "fixed_radius": {
     "distance_unit": "<distance_unit>",
     "value": <distance>
  }
}

If you use audience, you need to provide size while max_radius is optional

Note: this only works with ad_place_page_sets_async

 {
  "audience": {
     "size": <audience_size>,
     "max_radius": { // optional
       "distance_unit": "<distance_unit>",
       "value": <distance>
     }
  }
}

Best Practices for metadata

  • You must also provide locations; however, do not specify a radius in it. Alternately, if you use the locations parameter and provide radiuses, you should not also provide it for metadata.
  • The distance_unit must be mile or kilometer, and the value must be between 0.7 to 50 for mile or 1 to 80 for kilometer.
  • The size parameter in audience is the number of Accounts Center accounts in the radius as long as the radius is from 1 to 80 kilometers in length. If you provide a max_radius, the actual radius we calculate varies between 1 and max_radius.
  • If you specify audience for metadata, you must make your request with the asynchronous endpoint (ad_account_ID/ad_place_page_set_async).

Synchronous Requests

You can still use synchronous requests to create a PageSet.

curl -X POST \
  -d "name=<PAGESET_NAME>" \
  -d "parent_page=<PARENT_PAGE_ID>" \
  -d "pages=<LOCATIONS_JSON_STRUCTURE>" \
  -d "access_token=<ACCESS_TOKEN>" \
 https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/ad_place_page_sets

This returns a PageSet ID that you will use later.

Example Output

{
  "id": <PAGE_SET_ID>
}

If the number of pages is too large for a cURL call, you can create a text file containing the Locations JSON structure and pass it to the pages attribute with -F "pages=&lt;locations_json_structure.txt".

Step 2: Create a Campaign

Create an ad campaign with the objective set to STORE_VISITS and your main page ID as the promoted object.

See Ad Campaign, Reference.

Step 3: Create An Ad Set

Create an ad set to contain your ad. See Reference, Ad Set, Reference, Targeting specs and Reference, Page locations.

At delivery time, Facebook invalidates any ads targeting locations more than 50 miles away from the nearest page location, known as a local page.

curl \
  -F 'name=Store Visits Ad Set' \
  -F 'promoted_object={"place_page_set_id":"<PAGE_SET_ID>"}' \
  -F 'optimization_goal=REACH' \
  -F 'billing_event=IMPRESSIONS' \
  -F 'is_autobid=true' \
  -F 'daily_budget=1000' \
  -F 'campaign_id=<CAMPAIGN_ID>' \
  -F "targeting={
    'age_min' : <MIN_AGE>,
    'age_max' : <MAX_AGE>,
    'place_page_set_ids': ['<PAGE_SET_ID>'],
    'device_platforms': ['mobile','desktop'],
    'facebook_positions': ['feed']
   }" \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/adsets

Geographical Targeting

You can also target by geo_locations in store traffic campaigns.

Note: For this objective, you can only use geo_locations or place_page_set_ids in ad set targeting.

We support all types of geo_location targeting in Advanced Targeting and Placement, including targeting by countries, cities, and zip codes. You can also select location_types, such as recent, home, or travel_in.

You should still provide place_page_set_id in the promoted_object. This PageSet has to be a page set without any explicit set of locations. See Creating the PageSet with the Locations JSON struture to create this PageSet. However, in this case, do not pass the parameter pages.

First, create a PageSet you will later provide in a promoted object:

curl -X POST \
  -d "name=My geo targeting page set" \
  -d "parent_page=<PARENT_PAGE_ID>" \
  -d "access_token=<ACCESS_TOKEN>" \
  https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/ad_place_page_sets/

Note: You do not need to provide the pages parameter as you normally do.

Then, create an ad set with the store traffic objective targeting geo_locations:

curl \
  -F 'name=Store Traffic Ad Set' \
  -F 'promoted_object={"place_page_set_id":"<PAGE_SET_ID>"}' \
  -F 'optimization_goal=REACH' \
  -F 'billing_event=IMPRESSIONS' \
  -F 'is_autobid=true' \
  -F 'daily_budget=1000' \
  -F 'campaign_id=<CAMPAIGN_ID>' \
  -F "targeting={
    'geo_locations': {"countries":["US"],"location_types": ["home"]}, 
    'device_platforms': ['mobile','desktop'],
    'facebook_positions': ['feed']
  }" \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/adsets

We automatically deliver ads for the store which is closest to the person viewing your ad.

Step 4: Provide an Ad Creative

You can dynamically insert a creative based on someone's location. Customize your creative using a set of template placeholders and Facebook replaces the placeholders in your ads at runtime with data from the nearest page location.

Available placeholders:

  • {{page.hours.today}}
  • {{page.location.city}}
  • {{page.location.region}}
  • {{page.location.postcode}}
  • {{page.location.street_address}}
  • {{page.name}}
  • {{page.phone_number}}

The dynamic_ad_voice field allows you to control the voice of your ad:

  • If dynamic_ad_voice is set to DYNAMIC, The page name and profile picture in your ad post come from the nearest page location.
  • If dynamic_ad_voice is set to STORY_OWNER, he page name and profile picture in your ad post come from the main page location.

Call-To-Action

You can also dynamically add call-to-action buttons (CTAs) based on someone's location:

  • When using GET_DIRECTIONS or CALL_NOW, the CTA value field is not required. Users will automatically be directed to nearest location or prompted to call the nearest location phone number.
  • MESSAGE_PAGE is allowed only if dynamic_ad_voice is set to STORY_OWNER. Messages will be delivered to the main page.
  • Optional field. If not specified for individual ads, we display a Like Page button.

For details, see Reference, Ad Creative

dynamic_ad_voice Type call_to_action Type

DYNAMIC

CALL_NOW


GET_DIRECTIONS

STORY_OWNER

CALL_NOW


GET_DIRECTIONS


LEARN_MORE


MESSAGE_PAGE


ORDER_NOW


SHOP_NOW

Examples

Provide an ad creative using a dynamic page name and city:

curl \
  -F 'dynamic_ad_voice=DYNAMIC' \
  -F 'object_story_spec={ 
    "page_id": "<PARENT_PAGE_ID>", 
    "template_data": { 
      "description": "Ad Description", 
      "link": "<URL>", 
      "message": "Ad Message for {{page.location.city}}", 
      "name": "{{page.name}}", 
      "picture": "<IMAGE_URL>" 
    } 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/adcreatives

Ad creative with map card

To use a map card, add a place_data structure as a attachment in the child_attachments field for your ad creative.

In this example, the map with a Facebook store locator link is the second item in the child_attachments array. You must provide have at least one item in addition to the map card.

curl \
  -F 'dynamic_ad_voice=DYNAMIC' \
  -F 'object_story_spec={ 
    "page_id": "<PARENT_PAGE_ID>", 
    "template_data": { 
      "description": "Ad Description", 
      "link": "<URL>", 
      "message": "Ad Message for {{page.location.city}}", 
      "name": "{{page.name}}", 
      "child_attachments":[
        {
          "description": "Come visit us!",
          "link": "http://yourweburl.com",
          "name": "{{page.location.street_address}} - {{page.location.city}}",
          "call_to_action": {
            "type":"GET_DIRECTIONS"
          },
        },
        {
          "link": "https://fb.com/store_locator",
          "name": "Check out our stores.",
          "place_data": {
            "type":"DYNAMIC"
          },
        }
      ]
    } 
  }' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/adcreatives

Store Locator, Link Destination

When you create an ad, if you set the link to 'https://fb.com/store_locator', the ad appears with the store locator as the link destination.

Step 5: Create An Ad

Create an ad as follows:

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/<API_VERSION>/act_<AD_ACCOUNT_ID>/ads

To create ads for store traffic, your page and ad account must be approved for the store visits measurement. Otherwise, an error similar to Reach estimate isn't available because 'store_visits' isn't a valid action type displays.

Store Visits Measurement

Store visits is an estimated metric based on data from users with location services enabled. It ultimately offers store visit measurement and optimization for the store traffic objective. Store visit measurement is only available for campaigns with the store traffic objective.

Store visits are based on clicks and views of ads using the store traffic objective. It's an estimated number of visits to an advertiser's stores by Accounts Center accounts who have seen or clicked on each store's ads. You can configure the attribution window; you can choose to customize it based on 1-, 7- or 28-day clicks or views. The ad account's default attribution applies unless you customize the configuration. See Insights API, Attribution Window.

The features relate to reporting for the following items:

  • Store Visits — The number of estimated visits to your store as a result of your ads.
  • Cost per Store Visit — The average cost for each estimated visit to your stores as a result of your ads.

With Ads Manager

See the columns under ENGAGEMENT: ACTIONS. These columns appear in the reporting interface for store visits and the cost per store visit.

Note: Store visit data is only available for stores that Meta team confirms as measurable for a campaign.

With the Insights API

You can get data on store visits from the Insights API. We provide these additional fields in the general insights calls: cost_per_store_visit_action and store_visit_actions. See Insights, Reference.

Parameters

FieldDescription
point_estimate
int32

The point prediction of the value