The `PLACES_COUNT_PER_H3` function aggregates Places of Interest (POI) data into
standardized [H3 spatial grid cells](https://h3geo.org/docs/) at a specified
resolution. This function is the recommended pathway for regional density
analysis, competitive mapping, and generating hexagonal choropleth heatmaps.

To call the `PLACES_COUNT_PER_H3` function, use a SQL `FROM` clause because
the function returns a table.

## Syntax and parameters

```googlesql
SELECT * FROM `PROJECT_NAME.LINKED_DATASET_NAME.PLACES_COUNT_PER_H3`(
  filters
)
```

### Parameters

- **`PROJECT_NAME`**: The name of your Google Cloud project. If you don't specify a project name, your query will default to the active project.
- **`LINKED_DATASET_NAME`** : The name of your subscribed Places Insights dataset (for example, `places_insights___us`).
- **`filters`
  ([JSON](https://cloud.google.com/bigquery/docs/reference/standard-sql/json_functions))** : A JSON object constructed using `JSON_OBJECT` containing key-value filter parameters.

#### Required JSON Filters

- **`geography`
  ([GEOGRAPHY](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#geography_type))**: The bounding search area (Point, Linestring, or Polygon) to be indexed.
- **`h3_resolution` (INTEGER)** : The H3 cell resolution level (supported values range from `0` to `11`).

#### Optional JSON Filters

- Additional parameters such as `types`, `business_status`, `price_level`, and `min_rating` to filter the places counted within each cell. See the [complete list of filter
  parameters](https://developers.google.com/maps/documentation/placesinsights/reference/filter-params).

## Output table schema

The function returns a BigQuery table with one row per H3 cell index
intersecting your target geometry:

| Column name | Data type | Description |
|---|---|---|
| `h3_cell_index` | [STRING](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#string_type) | The unique H3 index identifier for the cell. |
| `geography` | [GEOGRAPHY](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#geography_type) | A polygon representing the physical boundary of the H3 cell. |
| `count` | [INTEGER](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#integer_types) | The total exact count of matching operational places within this specific H3 cell, or zero if no places match. |
| `sample_place_ids` | [ARRAY\<STRING\>](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#array_type) | An array of up to 250 Place IDs located within this cell, enabling direct ground-truth queries using the Places API. |

## Aggregate regional POI density using PLACES_COUNT_PER_H3

The function processes the bounding geography specified in your filters,
identifies all intersecting H3 hexagons at your target resolution, and returns
exact place counts and Place IDs for each hexagon.

### Example: Count wheelchair-accessible grocery and convenience stores in New York State

This query aggregates operational, wheelchair-accessible convenience and grocery
stores in New York State using an H3 resolution level of 8. The boundary
geometry of New York State is dynamically queried from the
`bigquery-public-data.geo_us_boundaries.states` public dataset.

```googlesql
-- Query POI count per H3 cell intersecting the New York State polygon boundary
SELECT *
FROM `PROJECT_NAME.places_insights___us.PLACES_COUNT_PER_H3`(
  JSON_OBJECT(
      'geography', (
        -- Dynamically retrieve the boundary geography for New York State
        SELECT state_geom
        FROM `bigquery-public-data.geo_us_boundaries.states`
        WHERE state = 'NY'
        LIMIT 1
      ),
      'types', ['grocery_store', 'convenience_store'],
      'business_status', ['OPERATIONAL'],
      'h3_resolution', 8,
      'wheelchair_accessible_entrance', TRUE
  )
)
ORDER BY count DESC;
```

### Response format

The query yields a row-by-row table mapping cells directly to spatial
counts:

![BigQuery results for H3 query.](https://developers.google.com/static/maps/documentation/placesinsights/images/place_count_h3_results.png)

> [!IMPORTANT]
> **Important:** The JSON object passed to `PLACES_COUNT_PER_H3` is subject to a strict **1 MB size limit** . Because the bounding geography is passed directly inside the `JSON_OBJECT` parameter under the `'geography'` key, complex spatial boundaries with thousands of vertices can exceed this limit. To prevent execution failures, use the [`ST_SIMPLIFY`](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_simplify) function to reduce vertex complexity before passing geometries to the function.

## Example: Count places per H3 cell filtered by brand

The following example uses the `brand_ids` filter to retrieve
place counts and sample place IDs for specific brands, such as Starbucks
`"1413758728321880760"` and Dunkin `"1314981297593671295"`:

```googlesql
DECLARE geo GEOGRAPHY;

-- Get the geography for New York City.
SET geo = (SELECT geometry FROM `bigquery-public-data.overture_maps.division_area`
  WHERE country = 'US' AND subtype = 'locality' AND names.primary = 'New York'  LIMIT 1);

SELECT * FROM `PROJECT_NAME.places_insights___us.PLACES_COUNT_PER_H3`(
  JSON_OBJECT(
      'geography', geo,
      'h3_resolution', 8,
      'brand_ids', ["1413758728321880760", "1314981297593671295"],
      'business_status', ['OPERATIONAL']
    )
);
```

## Visualize H3 results dynamically in Looker Studio

The following images show data from `PLACES_COUNT_PER_H3` displayed in Looker
Studio as a filled map. The darker the H3 cell, the higher the concentration of
results:

![Filled map for filtering wheelchair accessible convenience and grocery stores in New York.](https://developers.google.com/static/maps/documentation/placesinsights/images/place_count_h3_map.png)

To import your data into Looker Studio:

1. Run the function above in BigQuery to generate your results.
2. In the BigQuery results pane, click **Open in -\> Looker Studio**. Your results are automatically imported into Looker Studio.
3. Looker Studio creates a default report page and initializes it with a title,
   table, and bar graph of the results.

   ![Default report in Looker Studio.](https://developers.google.com/static/maps/documentation/placesinsights/images/default_data_view.png)
4. Select everything on the page and delete it.

5. Click **Insert -\> Filled map** to add a filled map to your report.

6. Under **Chart types -\> Setup**, configure the fields as shown below:

   ![Heatmap setup in Looker Studio.](https://developers.google.com/static/maps/documentation/placesinsights/images/heatmap_h3_function_fields.png)
7. The filled map appears as above. You can optionally select **Chart types -\>
   Style** to further configure the appearance of the map.

For more information on visualizing Places Insights results, see [Visualize
query results](https://developers.google.com/maps/documentation/placesinsights/visualize-data).

## Example: Query historical POI counts by H3 cell with specific filters

This example demonstrates how to query historical POI counts across an H3 spatial grid for a specific snapshot month using the `snapshot_date` filter. It defines a geographical search area using a buffer around a location, and applies additional criteria for EV charging connector counts using `max_ev_charge_connector_count` alongside specific `regular_opening_hours`.

```googlesql
SELECT *
FROM `PROJECT_NAME.places_insights___us.PLACES_COUNT_PER_H3`(
  JSON_OBJECT(
    'geography', ST_BUFFER(ST_GEOGPOINT(-74.0060, 40.7128), 5000), -- 5km radius around NYC
    'h3_resolution', 8,
    'business_status', ['OPERATIONAL'],
    'snapshot_date', '2026-01', -- Target snapshot month (YYYY-MM)
    'max_ev_charge_connector_count', 3, -- Maximum connector count
    'regular_opening_hours', JSON_OBJECT(
      'monday', [JSON_OBJECT('start_time', '09:00', 'end_time', '12:00')]
    )
  )
);
```