Unlike other assets, location assets are automatically created by the Google Ads API
after you create an asset set. First, create a location sync asset set and
attach it to the customer. Then, if you need to select a subset of the location
assets in the asset set for a campaign or ad group, create a location group
asset set and attach it to the campaign or ad group.

## Create a location sync asset set and attach it to the customer

1. [Create a **location sync** asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#create-location-sync).
2. [Attach it to a customer](https://developers.google.com/google-ads/api/docs/assets/location-assets#attach-location-sync) using [`CustomerAssetSetService`](https://developers.google.com/google-ads/api/reference/rpc/v26/CustomerAssetSetService).

### Create a location sync asset set

1. Create a new [`AssetSet`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSet).
   1. Set `type` to [`LOCATION_SYNC`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSetTypeEnum.AssetSetType#location_sync).
   2. Set `location_set` to a new [`LocationSet`](https://developers.google.com/google-ads/api/reference/rpc/v26/LocationSet).
2. In the new `LocationSet`,

   1. Set `location_ownership_type` based on your use case:
      - Set it to [`BUSINESS_OWNER`](https://developers.google.com/google-ads/api/reference/rpc/v26/LocationOwnershipTypeEnum.LocationOwnershipType#business_owner) if you own the business location.
      - Set it to [`AFFILIATE`](https://developers.google.com/google-ads/api/reference/rpc/v26/LocationOwnershipTypeEnum.LocationOwnershipType#affiliate) if you don't own the business location, but sell your products there.
   2. Set the `source` oneof field based on your use case:

      - Set `business_profile_location_set` if you want to sync with your
        locations in your
        [Google Business Profile](https://www.google.com/business/) account.

        When you create a `BusinessProfileLocationSet` to link Google Ads with a
        Google Business Profile account, you must provide an OAuth 2.0
        access token in the `http_authorization_token` field. This token
        acts as proof that you are authorizing Google Ads to access the location
        data from the specified Google Business Profile.

        The token must meet these requirements:
        - It must be generated for the Google Account (user or service account) whose email address is provided in the `email_address` field of the `BusinessProfileLocationSet`.
        - This account must have sufficient permissions to read the business locations within the Google Business Profile.
        - The OAuth 2.0 token must be obtained with the `https://www.googleapis.com/auth/business.manage` scope.

        For detailed instructions on how to generate an OAuth 2.0 access
        token, refer to
        [Using OAuth 2.0 to Access Google APIs](https://developers.google.com/identity/protocols/oauth2).
      - Set `chain_location_set` if you want to sync with locations in
        specified chain IDs.

      - Set `maps_location_set` if you want to manually add locations using
        [Place IDs](https://developers.google.com/maps/documentation/places/web-service/place-id).

After you complete these steps, the Google Ads API generates **location
assets** and adds them to the created location sync asset set for you, similar
to when you manually do so using
[`AssetSetAssetService`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSetAssetService). You don't need to
manipulate them unless you want to manually [add them to a static location
group asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#add-location-assets).

Only one active location sync asset set with
[`status`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSet#status) set to
[`ENABLED`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSetStatusEnum.AssetSetStatus#enabled) can exist
for a customer. If you need to create a different type of location sync asset
set, remove the existing one first.

### Attach the location sync asset set to a customer

Use
[`CustomerAssetSetService.MutateCustomerAssetSets`](https://developers.google.com/google-ads/api/reference/rpc/v26/CustomerAssetSetService/MutateCustomerAssetSets)
to attach the location sync asset set in the previous section to your customer.

## (Optional) Create a location group asset set and attach it to a campaign or an ad group

A **location group** asset set is necessary only if you need to select a subset
of location assets. This is due to campaigns and ad groups inheriting location
assets from the customer level.

Location group asset sets contain a subset of location assets of the **location
sync** asset set. You can dynamically create a location group asset set by
leveraging some features of Google Business Profile (like filtering by labels)
or chain IDs and chain locations. Alternatively, you can statically create a
location group asset set.

1. [Create a location group asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#create-location-group). The location group asset set can be **dynamic** or **static**.
2. [Attach the asset set to a campaign or to an ad group, depending on your
   need](https://developers.google.com/google-ads/api/docs/assets/location-assets#attach-location-group).
3. [(Optional) Add the previously generated assets to the newly created static
   location group asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#add-location-assets).

For a given customer, you can create multiple dynamic or static location group
asset sets.

### Create a location group asset set

Create a new [`AssetSet`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSet) and set
`location_group_parent_asset_set_id` to the ID of the previously created
location sync asset set.

Then, set some fields based on whether you want to create a dynamic or static
location group asset set.

#### Dynamic asset sets

Depending on the field you [set in `LocationSet`](https://developers.google.com/google-ads/api/docs/assets/location-assets#create-location-sync), set
the fields based on the following rule:

| If you set the following field | Then set [type](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSet#type) to | And set this field as the [asset_set_source](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSet#asset_set_source) oneof field |
|---|---|---|
| `business_profile_location_set` | `BUSINESS_PROFILE_DYNAMIC_LOCATION_GROUP` | `business_profile_location_group` |
| `chain_location_set` | `CHAIN_DYNAMIC_LOCATION_GROUP` | `chain_location_group` |

If you set `maps_location_set` when [creating the location sync asset
set](https://developers.google.com/google-ads/api/docs/assets/location-assets#create-location-sync), you won't be able to create a dynamic location
group asset set. This is because you've manually added locations by Place IDs
and there are no filtering features you can use for this type of locations.

#### Static asset sets

Set [`type`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSet#type) to
[`STATIC_LOCATION_GROUP`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSetTypeEnum.AssetSetType#static_location_group).
You can create static location group asset sets for any types of location
sync asset sets, no matter what fields (`business_profile_location_set`,
`chain_location_set`, or `maps_location_set`) you set in the
[`LocationSet`](https://developers.google.com/google-ads/api/reference/rpc/v26/LocationSet#source).

For **static** location group asset sets, you need to
[manually add the generated location assets to the location group asset
sets](https://developers.google.com/google-ads/api/docs/assets/location-assets#add-location-assets).

### Attach the asset set to a campaign or to an ad group

Use
[`CampaignAssetSetService.MutateCampaignAssetSets`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAssetSetService/MutateCampaignAssetSets)
to attach the [location group asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#create-location-group) to your
campaign.

Alternatively, use
[`AdGroupAssetSetService.MutateAdGroupAssetSets`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupAssetSetService/MutateAdGroupAssetSets)
if you want to attach the [location group asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#create-location-group) to
an ad group instead.

### (Optional) Add the location assets to the **static** location group asset set

This step is required only if you create a
[static location group asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#static-asset-sets) previously.

1. Use the [`asset_set_asset`](https://developers.google.com/google-ads/api/fields/v26/asset_set_asset) report to fetch the resource names of assets automatically generated for the [previously created location sync asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#create-location-sync). Use [filtering](https://developers.google.com/google-ads/api/docs/query/structure#where) to retrieve only the assets you want.
2. Add them to the [static location group asset set](https://developers.google.com/google-ads/api/docs/assets/location-assets#static-asset-sets) using [`AssetSetAssetService.MutateAssetSetAssets`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetSetAssetService/MutateAssetSetAssets).

### Manage Business Profile location IDs

When you use a `business_profile_location_set` and filter on
[`listing_id_filters`](https://developers.google.com/google-ads/api/reference/rpc/v26/DynamicBusinessProfileLocationGroupFilter#listing_id_filters%5B%5D) that are retrieved from the Business
Profile website or API, it may be necessary to convert these numeric values from
type `uint64` to `int64`. If your code generates a runtime error that your
Business Profile location ID is out of range when adding it to the
`listing_id_filters[]` repeated field, then you likely need to convert it using
any of the following examples:

### Java

    /**
     * Converts the business profile location ID to the format expected by the
     * DynamicBusinessProfileLocationGroupFilter.listing_id_filters[] repeated field.
     * The business profile location ID is an unsigned 64-bit integer, while the
     * listing_id_filters[] field expects signed 64-bit integers. This means that
     * for business profile location IDs that are out of range, we must perform the
     * two's complement to convert it into a signed int.
     *
     * @param businessProfileLocationId The ID of a Business Profile location ID.
     * @return a Business Profile location ID as a signed 64-bit integer (long).
     */
    public static long convertBusinessProfileLocationId(String businessProfileLocationId) {
        return Long.parseUnsignedLong(businessProfileLocationId);
    }

### C#

    /// <summary>
    /// Converts the business profile location ID to the format expected by the
    /// DynamicBusinessProfileLocationGroupFilter.listing_id_filters[] repeated field.
    /// The business profile location ID is an unsigned 64-bit integer, while the
    /// listing_id_filters[] field expects signed 64-bit integers. This means that
    /// for business profile location IDs that are out of range, we must perform the
    /// two's complement to convert it into a signed int.
    /// </summary>
    /// <param name="businessProfileLocationId">The ID of a Business Profile location.</param>
    /// <returns>The converted business location ID in signed 64 bit.</returns>
    public long ConvertBusinessProfileLocationId(ulong businessProfileLocationId)
    {
      return unchecked((long)businessProfileLocationId);
    }

### PHP

    /**
    * Converts a business profile location ID to a signed 64 bit integer.
    *
    * Converts the business profile location ID to the format expected by the
    * DynamicBusinessProfileLocationGroupFilter.listing_id_filters[] repeated field.
    * The business profile location ID is an unsigned 64-bit integer, while the
    * listing_id_filters[] field expects signed 64-bit integers. This means that
    * for business profile location IDs that are out of range, we must perform the
    * two's complement to convert it into a signed int.
    *
    * @param string $businessProfileLocationId the ID of a Business Profile location
    * @return int the converted business location ID in signed 64 bit
    */
    public static function convertBusinessProfileLocationId(string $businessProfileLocationId): int
    {
        $unsignedMax = '18446744073709551615'; // 2^64 - 1
        $signedMax = '9223372036854775807'; // 2^63 - 1

        // Check if the business profile location ID is within 64 bit range.
        // If not, throw an error.
        if (bccomp($businessProfileLocationId, '0') < 0 || bccomp($businessProfileLocationId, $unsignedMax) > 0) {
            throw new InvalidArgumentException(
                'The given business profile location id is outside of the range for a 64 bit integer.'
            );
        }

        // Check if the business profile location ID is in signed 64 bit range.
        // If it's not, convert it to its two's complement.
        if (bccomp($businessProfileLocationId, $signedMax) > 0) {
            // Two's complement: ID - 2^64
            return (int) bcsub($businessProfileLocationId, '18446744073709551616');
        }

        return (int) $businessProfileLocationId;
    }

### Python

    import ctypes

    def convert_business_profile_location_id(business_profile_location_id):
        """Converts a business profile location ID to a signed 64 bit integer.

        Converts the business profile location ID to the format expected by the
        DynamicBusinessProfileLocationGroupFilter.listing_id_filters[] repeated field.
        The business profile location ID is an unsigned 64-bit integer, while the
        listing_id_filters[] field expects signed 64-bit integers. This means that
        for business profile location IDs that are out of range, we must perform the
        two's complement to convert it into a signed int.

        Args:
            business_profile_location_id: the ID of a Business Profile location ID.

        Returns:
            a Business Profile location ID as a signed 64 bit integer.
        """
        # Check if the business profile location ID is within 64 bit range.
        # If not, throw an error.
        if business_profile_location_id < 0 or business_profile_location_id >= 2 ** 64:
            raise ValueError(
                "The given business profile location id is outside of the range for a 64 bit integer."
            )
        # Check if the business profile location ID is in signed 64 bit range.
        # If it's not, convert it to its two's complement.
        elif business_profile_location_id >= 2 ** 63:
            return ctypes.c_int64(business_profile_location_id).value
        else:
            return business_profile_location_id

### Ruby

    # Converts the business profile location ID to the format expected by the
    # DynamicBusinessProfileLocationGroupFilter.listing_id_filters[] repeated field.
    # The business profile location ID is an unsigned 64-bit integer, while the
    # listing_id_filters[] field expects signed 64-bit integers. This means that
    # for business profile location IDs that are out of range, we must perform the
    # two's complement to convert it into a signed int.
    # Since Ruby supports arbitrary precision numbers, we have to calculate it
    # manually.
    LONG_MAX = 2 ** 63
    ULONG_MAX = LONG_MAX * 2
    def convert_business_profile_location_id(business_profile_location_id)
      # Check if the business profile location ID is within 64 bit range.
      # If not, throw an error.
      if business_profile_location_id < 0 || business_profile_location_id >= 2 ** 64
        raise "The given business profile location id is outside of the range for a 64 bit integer."
      # Check if the business profile location ID is in signed 64 bit range.
      # If it's not, convert it to its two's complement.
      elsif business_profile_location_id >= 2**63
        -1 * (ULONG_MAX - business_profile_location_id)
      else
        business_profile_location_id
      end
    end

### Perl

    use bigint;

    # Converts the business profile location ID to the format expected by the
    # DynamicBusinessProfileLocationGroupFilter.listing_id_filters[] repeated field.
    # The business profile location ID is an unsigned 64-bit integer, while the
    # listing_id_filters[] field expects signed 64-bit integers. This means that
    # for business profile location IDs that are out of range, we must perform the
    # two's complement to convert it into a signed int.
    sub convert_business_profile_location_id {
      my ($business_profile_location_id) = @_;

      # Check if the business profile location ID is within 64 bit range.
      # If not, throw an error.
      if ($business_profile_location_id < 0 || $business_profile_location_id >= 2**64) {
        die "The given business profile location id is outside of the range for a 64 bit integer";
      # Check if the business profile location ID is in signed 64 bit range.
      # If it's not, convert it to its two's complement.
      } elsif ($business_profile_location_id >= 2**63) {
        return -1 * (2**64 - $business_profile_location_id);
      } else {
        return $business_profile_location_id;
      }
    }