To retrieve cost and utilization data with App Optimize API, you first create a report. This resource acts as a persistent definition for the data you want to analyze, specifying parameters like the scope, dimensions, time range, and filters.
After you create a report, the API generates the requested data asynchronously. You then use the report's resource name to fetch the resulting dataset.
The workflow is therefore:
- You create a report specifying your criteria.
- The system processes this request asynchronously.
- When the operation is complete, you read the resulting data.
This document details the structure and configurable parameters of App Optimize API reports, including available dimensions, metrics, and filtering options, and explains the format of the data returned.
For information about limitations for cost and utilization, see Understand the data.
Define a report
To create a report, you define a Report resource with the following
configuration parameters, which are described in the next subsections:
| Parameter | Type | Description |
|---|---|---|
scopes |
Array | The project or App Hub application to analyze. You must provide exactly one scope element. |
dimensions |
Array | The attributes to retrieve and group the data by, including time-based groupings. |
metrics |
Array | The specific measurements to return. |
filter |
String | A Common Expression Language (CEL) expression to narrow down the data, including time ranges. |
Scopes
The scopes field defines the set of resources App Optimize API will
analyze. Although the field is an array, you must specify exactly one element,
which can be either a project or an App Hub application:
project: a string representing a Google Cloud project. It must be formatted as:projects/PROJECT_IDReplace
PROJECT_IDwith the ID your Google Cloud project. For example,projects/my-project-1.application: a string representing the full resource name of an App Hub application. It must be formatted as:projects/PROJECT_ID/locations/LOCATION/applications/APPLICATION_IDReplace the following:
PROJECT_ID: the ID of the App Hub host project.LOCATION: the region of the App Hub application, such asus-central1.APPLICATION_ID: the ID of the App Hub application.
For example,
projects/my-host-proj/locations/us-central1/applications/my-app.
Here are example scopes arrays in JSON for a report creation request, showing
a single scope element:
Scoping by project:
"scopes": [ { "project": "projects/my-project-1" } ]Scoping by application:
"scopes": [ { "application": "projects/my-host-proj/locations/us-central1/applications/my-app" } ]
Dimensions
Dimensions determine how what data is returned and how the data is grouped.
For example, if you select project and product_display_name, the output
contains one row for every unique combination of project and product name
values found in the data.
Here is a table of supported dimensions:
| Dimension | Type | Description | Example value |
|---|---|---|---|
project |
STRING | The Google Cloud project ID. | projects/my-project |
application |
STRING | The App Hub application. | projects/my-project/locations/us-central1/applications/my-app |
service_or_workload |
STRING | The App Hub service or workload. | projects/my-project/locations/us-central1/applications/my-app/services/my-service |
resource |
STRING | The full resource name. | //compute.googleapis.com/projects/my-project/zones/us-central1-a/instances/vm-1 |
resource_type |
STRING | The API resource type. | compute.googleapis.com/Instance |
location |
STRING | The Google Cloud region or multi-region. | us-east1 |
sku |
STRING | The billing SKU ID. | 4496-8C0D-228F |
product_display_name |
STRING | The Google Cloud product name. | Compute Engine |
month |
STRING | The year and month. | 2024-01 |
day |
STRING | The year, month, and day. | 2024-01-10 |
hour |
STRING | The year, month, day, and hour. | 2024-01-10T00 |
The location dimension represents the Google Cloud region or multi-region
to which costs and usage are attributed. How this location is reported depends
on the location settings of the resources in the report scope:
- For resources deployed in a specific zone, such as
us-central1-a, the costs and usage are aggregated and attributed to the parent region. In this example, thelocationdimension would showus-central1. - For resources deployed in a region, such as
us-central1, thelocationdimension reflects that specific region. - For resources deployed or configured for a multi-region, such as
us, thelocationdimension reflects that multi-region.
Time dimensions
To aggregate results by time, include at least one time dimension, such as
month, day, or hour, in the dimensions list. Bear in mind that:
- All time dimensions use Pacific Time and respect Daylight Saving Time (DST).
- Formats follow ISO 8601.
- If the time range in the
filterdoes not perfectly align with the selected time dimension's granularity, the range is expanded to cover the full periods. For example, filtering for part of a day withdimension: ["month"]will include data for the entire month.
Metrics
Metrics are the quantitative values you want to measure for each group defined by your dimensions. The supported metrics are:
| Metric | Type | Description |
|---|---|---|
cost |
RECORD | The monetary cost in the requested currency. |
cpu_mean_utilization |
FLOAT64 | Average CPU utilization (0.0 to 1.0). |
cpu_p95_utilization |
FLOAT64 | 95th percentile CPU utilization (0.0 to 1.0). |
cpu_usage_core_seconds |
INT64 | Total CPU work performed. |
cpu_allocation_core_seconds |
INT64 | Total CPU capacity provisioned. |
memory_mean_utilization |
FLOAT64 | Average memory utilization (0.0 to 1.0). |
memory_p95_utilization |
FLOAT64 | 95th percentile memory utilization (0.0 to 1.0). |
memory_usage_byte_seconds |
INT64 | Total memory used over time. |
memory_allocation_byte_seconds |
INT64 | Total memory provisioned over time. |
Valid combinations
Not all dimensions can be combined with every metric in App Optimize API. The following table shows examples of valid dimension sets and the metrics you can use with them. The API will return an error if an invalid combination is requested; refer to that error for valid combinations.
| Dimensions | Supports cost metric |
Supports cpu_mean_utilization metric |
|---|---|---|
application, product_display_name |
||
application |
||
location, product_display_name, project, resource, resource_type, sku |
||
location, product_display_name, project, resource, resource_type |
||
location, product_display_name, project, service_or_workload |
||
location, product_display_name, project, sku |
||
product_display_name, project |
||
product_display_name, resource_type |
||
product_display_name, resource |
||
product_display_name |
||
project |
Filters
Use the filter field to narrow down the data using a CEL string.
You can build your filter expressions using any of the fields listed in the
Dimensions table.
Filtering must conform to these constraints:
- All string field predicates must use exact string matches. For example,
location == 'us-east1'. - Multiple predicates referring to the same string field must be joined
using the logical OR operator,
||. For example,location == 'us-east1' || location == 'us-west1'. - All other predicates must be joined using the logical AND operator,
&&. - A predicate on a time dimension, such as
day, specifying the start time must use the greater-than-or-equal-to comparison,>=. - A predicate on a time dimension specifying the end time must use the
less-than comparison,
<.
Time range
If the filter omits time dimensions (month, day, hour), the report
defaults to a seven-day range ending at the previous Pacific Time midnight,
respecting DST. The maximum date range is 90 days before the current date, and
the start time must be within the 90-day time window.
For example, if the current Pacific Time is
2026-01-05T12:00:00, the default range is 2025-12-29T00:00:00 to
2026-01-05T00:00:00 Pacific Time. The earliest start time for the time
range is 2025-10-07T00:00:00.
Cloud Run metrics are only available for six weeks before the current date.
Example filters
Here are some examples of how you can structure your CEL filter strings:
To filter the report data for a specific resource type, use the
==operator on theresource_typedimension:resource_type == 'compute.googleapis.com/Instance'To include only data from a single location, filter on the
locationdimension:location == 'us-east1'To include data from a specific list of locations, use the
||operator to combine conditions on thelocationdimension:location == 'us-east1' || location == 'us-west1'To get data within a specific time range using hourly granularity, you can filter on the
hourdimension. This example includes data from the start of 2024-01-01 up to, but not including, 2024-02-01:hour >= timestamp('2024-01-01T00:00:00Z') && hour < timestamp('2024-02-01T00:00:00Z')To filter for whole days, use the
daydimension. Note that day boundaries are interpreted in Pacific Time, so specifying the offset is best practice. This example includes all data for 2024-03-15 and 2024-03-16:day >= timestamp('2024-03-15T00:00:00-07:00') && day < timestamp('2024-03-17T00:00:00-07:00')Similarly, you can filter by calendar months using the
monthdimension, again being mindful of Pacific Time for the exact boundaries. This example includes all data for October and November 2025:month >= timestamp('2025-10-01T00:00:00-07:00') && month < timestamp('2025-12-01T00:00:00-08:00')To get data from the last 72 hours, use the
now()andduration()functions on thehourdimension:hour >= now() - duration('72h')To get data from the last seven days, you can use
duration()with thehourdimension:hour >= now() - duration('168h')Filtering for a specific calendar month, like the previous one, requires calculating the start and end timestamps in your application code. You then insert those calculated timestamps into the CEL expression. Conceptually, it might look like this, filtering on the
daydimension:day >= timestamp('START_OF_LAST_MONTH') && day < timestamp('START_OF_THIS_MONTH')Replace the following:
START_OF_LAST_MONTH: the ISO 8601 timestamp string representing the very beginning of the previous month in the Pacific Time zone, such as2025-12-01T00:00:00-08:00.START_OF_THIS_MONTH: the ISO 8601 timestamp string representing the very beginning of the current month in the Pacific Time zone, such as2026-01-01T00:00:00-08:00.
You need to calculate these exact timestamp strings in your application code, taking into account the current date, time zone (Pacific Time), and Daylight Saving Time transitions.
You can combine string and time filters using the
&&operator. This example filters for two locations within a specific two-month period:(location == 'us-east1' || location == 'us-west1') && hour >= timestamp('2023-12-01T00:00:00Z') && hour < timestamp('2024-02-01T00:00:00Z')Here's a more complex example combining
resource_type,project, and aday-based time range:resource_type == 'compute.googleapis.com/Instance' && project == 'projects/my-project' && day >= timestamp('2025-01-01T00:00:00-08:00') && day < timestamp('2025-02-01T00:00:00-08:00')
Report data structure
When you successfully read a report, the service returns the
data as columns and rows.
Columns
The columns array describes the schema of the data, in the order that each
field appears in the rows. Each object in the columns array has a name,
type, and sometimes nested columns if the type is RECORD.
- Dimensions you requested appear as fields with type
STRING. - Metrics you requested appear as fields with types like
INT64,FLOAT64, orRECORDfor complex types likecost.
For example, with the REST API, if you request dimensions: ["application", "product_display_name"]
and metrics: ["cost", "cpu_mean_utilization"], then App Optimize API
in response generates a columns array like this:
"columns": [
{
"name": "application",
"type": "STRING",
"mode": "NULLABLE"
},
{
"name": "product_display_name",
"type": "STRING",
"mode": "NULLABLE"
},
{
"name": "cost",
"type": "RECORD",
"mode": "NULLABLE",
"columns": [
{
"name": "currency_code",
"type": "STRING",
"mode": "NULLABLE"
},
{
"name": "units",
"type": "INT64",
"mode": "NULLABLE"
},
{
"name": "nanos",
"type": "INT64",
"mode": "NULLABLE"
}
]
},
{
"name": "cpu_mean_utilization",
"type": "FLOAT64",
"mode": "NULLABLE"
}
]
Rows
The rows field contains the actual data. Each row is an array of values
representing a single record. The order of values within each inner array
corresponds directly to the order of the fields defined in the columns array.
Continuing the example where application, product_display_name, cost, and
cpu_mean_utilization were requested from the REST API, a single row in the
generated rows array might look like this:
"rows": [
[
"//apphub.googleapis.com/projects/my-proj/locations/us-central1/applications/my-app",
"Compute Engine",
{
"currency_code": "USD",
"units": "12",
"nanos": 750000000
},
0.65
],
[
"//apphub.googleapis.com/projects/my-proj/locations/us-east1/applications/another-app",
"Cloud Storage",
{
"currency_code": "USD",
"units": "5",
"nanos": 200000000
},
0.15
]
]
The following table visualizes how the values within a single row array map to
the schema defined in the columns array, using the index of the value in the
row array:
| Index within row | Corresponding column | Type | Example value |
|---|---|---|---|
| 0 | application |
STRING | "//apphub.googleapis.com/.../applications/my-app" |
| 1 | product_display_name |
STRING | "Cloud Storage" |
| 2 | cost |
RECORD | { "currency_code": "USD", "units": "10", ... } |
| 3 | cpu_mean_utilization |
FLOAT64 | 0.65 |
Each element in the rows list is an array where the order of values matches
the order of field definitions in the columns array. Thus, the value at
index n in any given row array corresponds to the column defined at index n
in the columns array.
Interpreting cost metrics
When a report includes the cost metric, the value is returned as a RECORD
containing the following fields, based on the standard
google.type.Money type:
| Field | Type | Description |
|---|---|---|
currency_code |
STRING | The three-letter ISO 4217 currency code, such as "USD". |
units |
INT64 | The whole units of the amount. |
nanos |
INT64 | The nano (10-9) units of the amount. Must be between -999,999,999 and +999,999,999 inclusive. |
To get the full monetary value, you combine the units and the nanos fields.
The nanos field represents the fractional part of the currency value.
For example:
If
currency_codeis "USD",unitsis106, andnanosis321590000: The value is 106 + (321,590,000 / 1,000,000,000) = 106.32159 USD.If
currency_codeis "EUR",unitsis5, andnanosis750000000: The value is 5 + (750,000,000 / 1,000,000,000) = 5.75 EUR.
You would typically use a standard currency formatting library to display this value in a user-friendly format, including the appropriate currency symbol.
For more information on the data returned by the API and to understand its limitations, see Understand the data.
Report expiry
Each report is automatically deleted from the App Optimize API service
24 hours after the report's creation. After this time, the report and its data
cannot be retrieved through the API. To check a report's scheduled expiration
time, obtain its metadata and view the expireTime
field.