Creating listing groups for Things to do ad groups follows the same structural
hierarchy and tree-building process as
[Hotel Ads listing groups](https://developers.google.com/google-ads/api/docs/hotel-ads/create-listing-groups).

To partition your Things to do inventory, use the specialized activity
dimensions available in [`ListingDimensionInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ListingDimensionInfo):

- [`ActivityCountryInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ActivityCountryInfo): Filters by the destination country (`value`), using a Geo Target Constant resource name (`geoTargetConstants/{criterion_id}`, such as `"geoTargetConstants/2840"` for the US).
- [`ActivityStateInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ActivityStateInfo): Filters by the destination state or region (`value`), using a Geo Target Constant resource name (`geoTargetConstants/{criterion_id}`).
- [`ActivityCityInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ActivityCityInfo): Filters by the destination city (`value`), using a Geo Target Constant resource name (`geoTargetConstants/{criterion_id}`, such as `"geoTargetConstants/1023191"` for New York City).
- [`ActivityRatingInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ActivityRatingInfo): Filters by the activity star or user rating (`value`, an integer from `1` to `5`, where `5` is the best).
- [`ActivityIdInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ActivityIdInfo): Filters by the specific activity ID defined in your Things to do Center feed (`value`).

## Dimension hierarchy rules

When building a Things to do listing group tree, follow these rules:

1. **Root node** : Every listing group tree must start with a single root `AdGroupCriterion` whose `listing_group.type` is `SUBDIVISION` (or `UNIT` if you want a single catch-all node) and whose `case_value` is unset.
2. **Subdivisions and units** : Intermediate branches must set `type` to `SUBDIVISION`, while leaf nodes must set `type` to `UNIT`. Setting [`cpc_bid_micros`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterion#cpc_bid_micros) on `UNIT` nodes is optional for Things to do campaigns because bidding is managed automatically by the campaign's `MaximizeConversionValue` strategy. To exclude a leaf unit from serving, set `negative = true` on its `AdGroupCriterion`.
3. **Fallback ("Everything else") nodes** : Every subdivision must be completely partitioned. All immediate children of a subdivision must use the same `ListingDimensionInfo` subtype, and one child must be an empty instance of that subtype to capture all remaining inventory.

The following tree illustrates a valid hierarchy partitioned by country, city,
and activity ID:

    Root (SUBDIVISION)
     ├── ActivityCountryInfo: "geoTargetConstants/2840" (US, SUBDIVISION)
     │    ├── ActivityCityInfo: "geoTargetConstants/1023191" (New York, SUBDIVISION)
     │    │    ├── ActivityIdInfo: "activity_123" (UNIT, biddable)
     │    │    └── ActivityIdInfo: <empty> (UNIT, "Everything else in New York")
     │    └── ActivityCityInfo: <empty> (UNIT, "Everything else in US")
     └── ActivityCountryInfo: <empty> (UNIT, negative=true, excluded)

## Code example

The following Python example creates a root `SUBDIVISION` using a temporary ID
(`-1`) and partitions it by `ActivityCountryInfo` into a targeted unit for the
US (`"geoTargetConstants/2840"`) and an excluded fallback unit for all other
countries:

    ad_group_service = client.get_service("AdGroupService")
    ad_group_criterion_service = client.get_service("AdGroupCriterionService")
    ad_group_resource_name = ad_group_service.ad_group_path(
        customer_id, ad_group_id
    )
    operations = []

    # 1. Create the root SUBDIVISION node with temporary criterion ID -1.
    root_op = client.get_type("AdGroupCriterionOperation")
    root = root_op.create
    root.resource_name = ad_group_criterion_service.ad_group_criterion_path(
        customer_id, ad_group_id, -1
    )
    root.status = client.enums.AdGroupCriterionStatusEnum.ENABLED
    root.listing_group.type_ = client.enums.ListingGroupTypeEnum.SUBDIVISION
    operations.append(root_op)

    # 2. Create a child UNIT node targeting activities in the US.
    us_op = client.get_type("AdGroupCriterionOperation")
    us_unit = us_op.create
    us_unit.ad_group = ad_group_resource_name
    us_unit.status = client.enums.AdGroupCriterionStatusEnum.ENABLED
    us_unit.listing_group.type_ = client.enums.ListingGroupTypeEnum.UNIT
    us_unit.listing_group.parent_ad_group_criterion = root.resource_name
    us_unit.listing_group.case_value.activity_country.value = "geoTargetConstants/2840"
    operations.append(us_op)

    # 3. Create the required fallback ("Everything else") UNIT node.
    other_op = client.get_type("AdGroupCriterionOperation")
    other_unit = other_op.create
    other_unit.ad_group = ad_group_resource_name
    other_unit.negative = True
    other_unit.listing_group.type_ = client.enums.ListingGroupTypeEnum.UNIT
    other_unit.listing_group.parent_ad_group_criterion = root.resource_name
    client.copy_from(
        other_unit.listing_group.case_value.activity_country,
        client.get_type("ActivityCountryInfo"),
    )
    operations.append(other_op)

    response = ad_group_criterion_service.mutate_ad_group_criteria(
        customer_id=customer_id, operations=operations
    )

## What's next

- Query activity performance metrics in [Things to do reporting](https://developers.google.com/google-ads/api/docs/things-to-do-ads/reporting).