The Reporting sub-API lets you retrieve performance data and insights about products within your Merchant Center account. You can use this sub-API to do the following:
- Identify product issues.
- Discover your top-performing products and brands.
- Gain a better understanding of your overall product landscape.
This guide walks through common use cases to help you use reporting effectively.
You interact with the Reporting sub-API primarily through the reports.search
method. This method requires you to submit a query written in the Merchant
Center Query Language (MCQL). MCQL lets you:
- Specify the data fields to retrieve.
- Filter results based on various segments, such as date ranges or country codes.
- Control the ordering and limits of your results.
Understand the Merchant Center Query Language
You retrieve reports by sending queries written in the Merchant Center Query
Language (MCQL). The language lets you select data from different resources
(called "views", like product_performance_view
or product_view
), filter by
segments (like date
or marketing_method
), select metrics (like clicks
or impressions
), order the results, and limit the number of results.
For detailed information on the query language structure and available views, fields, and metrics, see the Merchant Center Query Language grammar .
Prerequisites
Before you use the Reporting sub-API, verify that you have a Merchant Center account that contains product data.
For specific data (performance reports) you need to have the Performance and insights role. For more information, see I need help with people and access levels . and Requirements .
Example: Identify product issues
You can identify issues affecting your products to take corrective actions. This helps you maintain compliance and improve the visibility of your products. For example, the following query retrieves all issues for products in your account, helping you verify whether your products meet policy and data quality requirements.
Calling
POST https://merchantapi.googleapis.com/reports/v1/accounts/ {ACCOUNT_ID}
/reports:search
with the following request body:
SELECT
id
,
offer_id
,
feed_label
,
title
,
aggregated_reporting_context_status
,
item_issues
FROM
product_view
WHERE
aggregated_reporting_context_status
=
'NOT_ELIGIBLE_OR_DISAPPROVED'
will produce a response like:
{
"results"
:
[
{
"productView"
:
{
"id"
:
"en~US~id0"
"offerId"
:
"id0"
,
"feedLabel"
:
"US"
,
"aggregatedReportingContextStatus"
:
"NOT_ELIGIBLE_OR_DISAPPROVED"
,
"itemIssues"
:
[
{
"type"
:
{
"code"
:
"invalid_string_value"
,
"canonicalAttribute"
:
"n:product_code"
},
"severity"
:
{
"severityPerReportingContext"
:
[
{
"reportingContext"
:
"SHOPPING_ADS"
,
"disapprovedCountries"
:
[
"US"
]
},
{
"reportingContext"
:
"FREE_LISTINGS"
,
"disapprovedCountries"
:
[
"US"
]
}
],
"aggregatedSeverity"
:
"DISAPPROVED"
},
"resolution"
:
"MERCHANT_ACTION"
},
{
"type"
:
{
"code"
:
"apparel_missing_brand"
,
"canonicalAttribute"
:
"n:brand"
},
"severity"
:
{
"severityPerReportingContext"
:
[
{
"reportingContext"
:
"SHOPPING_ADS"
,
"disapprovedCountries"
:
[
"US"
]
}
],
"aggregatedSeverity"
:
"DEMOTED"
},
"resolution"
:
"MERCHANT_ACTION"
}
]
}
}
]
}
Following code samples show how to filter disapproved products.
Java
import
com.google.api.gax.core.FixedCredentialsProvider
;
import
com.google.auth.oauth2.GoogleCredentials
;
import
com.google.shopping.merchant.products.v1.GetProductRequest
;
import
com.google.shopping.merchant.products.v1.Product
;
import
com.google.shopping.merchant.products.v1.ProductsServiceClient
;
import
com.google.shopping.merchant.products.v1.ProductsServiceSettings
;
import
com.google.shopping.merchant.reports.v1.ReportRow
;
import
com.google.shopping.merchant.reports.v1.ReportServiceClient
;
import
com.google.shopping.merchant.reports.v1.ReportServiceClient.SearchPagedResponse
;
import
com.google.shopping.merchant.reports.v1.ReportServiceSettings
;
import
com.google.shopping.merchant.reports.v1.SearchRequest
;
import
shopping.merchant.samples.utils.Authenticator
;
import
shopping.merchant.samples.utils.Config
;
/**
* This class demonstrates how to get the list of all the disapproved products for a given merchant
* center account.
*/
public
class
FilterDisapprovedProductsSample
{
// Gets the product details for a given product using the GetProduct method.
public
static
void
getProduct
(
GoogleCredentials
credential
,
Config
config
,
String
productName
)
throws
Exception
{
// Creates service settings using the credentials retrieved above.
ProductsServiceSettings
productsServiceSettings
=
ProductsServiceSettings
.
newBuilder
()
.
setCredentialsProvider
(
FixedCredentialsProvider
.
create
(
credential
))
.
build
();
// Calls the API and catches and prints any network failures/errors.
try
(
ProductsServiceClient
productsServiceClient
=
ProductsServiceClient
.
create
(
productsServiceSettings
))
{
// The name has the format: accounts/{account}/products/{productId}
GetProductRequest
request
=
GetProductRequest
.
newBuilder
().
setName
(
productName
).
build
();
Product
response
=
productsServiceClient
.
getProduct
(
request
);
System
.
out
.
println
(
response
);
}
catch
(
Exception
e
)
{
System
.
out
.
println
(
e
);
}
}
// Filters the disapproved products for a given Merchant Center account using the Reporting API.
// Then, it prints the product details for each disapproved product.
public
static
void
filterDisapprovedProducts
(
Config
config
)
throws
Exception
{
GoogleCredentials
credential
=
new
Authenticator
().
authenticate
();
ReportServiceSettings
reportServiceSettings
=
ReportServiceSettings
.
newBuilder
()
.
setCredentialsProvider
(
FixedCredentialsProvider
.
create
(
credential
))
.
build
();
try
(
ReportServiceClient
reportServiceClient
=
ReportServiceClient
.
create
(
reportServiceSettings
))
{
// The parent has the format: accounts/{accountId}
String
parent
=
String
.
format
(
"accounts/%s"
,
config
.
getAccountId
().
toString
());
// The query below is an example of a query for the productView that gets product informations
// for all disapproved products.
String
query
=
"SELECT offer_id,"
+
"id,"
+
"title,"
+
"price"
+
" FROM product_view"
// aggregated_reporting_context_status can be one of the following values:
// NOT_ELIGIBLE_OR_DISAPPROVED, ELIGIBLE, PENDING, ELIGIBLE_LIMITED,
// AGGREGATED_REPORTING_CONTEXT_STATUS_UNSPECIFIED
+
" WHERE aggregated_reporting_context_status = 'NOT_ELIGIBLE_OR_DISAPPROVED'"
;
// Create the search report request.
SearchRequest
request
=
SearchRequest
.
newBuilder
().
setParent
(
parent
).
setQuery
(
query
).
build
();
System
.
out
.
println
(
"Sending search report request for Product View."
);
// Calls the Reports.search API method.
SearchPagedResponse
response
=
reportServiceClient
.
search
(
request
);
System
.
out
.
println
(
"Received search reports response: "
);
// Iterates over all report rows in all pages and prints each report row in separate line.
// Automatically uses the `nextPageToken` if returned to fetch all pages of data.
for
(
ReportRow
row
:
response
.
iterateAll
())
{
System
.
out
.
println
(
"Printing data from Product View:"
);
System
.
out
.
println
(
row
);
// Optionally, you can get the full product details by calling the GetProduct method.
String
productName
=
"accounts/"
+
config
.
getAccountId
().
toString
()
+
"/products/"
+
row
.
getProductView
().
getId
();
System
.
out
.
println
(
"Getting full product details by calling GetProduct method:"
);
getProduct
(
credential
,
config
,
productName
);
}
}
catch
(
Exception
e
)
{
System
.
out
.
println
(
"Failed to search reports for Product View."
);
System
.
out
.
println
(
e
);
}
}
public
static
void
main
(
String
[]
args
)
throws
Exception
{
Config
config
=
Config
.
load
();
filterDisapprovedProducts
(
config
);
}
}
Apps Script
/**
* Demonstrates how to filter disapproved products using the Merchant API Reports service.
*/
function
filterDisapprovedProducts
()
{
// IMPORTANT:
// Enable the Merchant API Reports sub-API Advanced Service and call it
// "MerchantApiReports"
// Enable the Merchant API Products sub-API Advanced Service and call it
// "MerchantApiProducts"
// Replace this with your Merchant Center ID.
const
accountId
=
'<INSERT_MERCHANT_CENTER_ID>'
;
// Construct the parent name
const
parent
=
'accounts/'
+
accountId
;
try
{
console
.
log
(
'Sending search Report request'
);
// Set pageSize to the maximum value (default: 1000)
let
pageSize
=
1000
;
let
pageToken
;
// The query below is an example of a query for the productView that gets product informations
// for all disapproved products.
let
query
=
'SELECT offer_id,'
+
'id,'
+
'price,'
+
'title'
+
' FROM product_view'
+
' WHERE aggregated_reporting_context_status = "NOT_ELIGIBLE_OR_DISAPPROVED"'
;
// Call the Reports.search API method. Use the pageToken to iterate through
// all pages of results.
do
{
response
=
MerchantApiReports
.
Accounts
.
Reports
.
search
({
query
,
pageSize
,
pageToken
},
parent
);
for
(
const
reportRow
of
response
.
results
)
{
console
.
log
(
"Printing data from Product View:"
);
console
.
log
(
reportRow
);
// OPTIONALLY, you can get the full product details by calling the GetProduct method.
let
productName
=
parent
+
"/products/"
+
reportRow
.
getProductView
().
getId
();
product
=
MerchantApiProducts
.
Accounts
.
Products
.
get
(
productName
);
console
.
log
(
product
);
}
pageToken
=
response
.
nextPageToken
;
}
while
(
pageToken
);
// Exits when there is no next page token.
}
catch
(
e
)
{
console
.
log
(
'ERROR!'
);
console
.
log
(
'Error message:'
+
e
.
message
);
}
}
PHP
use Google\ApiCore\ApiException;
use Google\Shopping\Merchant\Products\V1\Client\ProductsServiceClient;
use Google\Shopping\Merchant\Products\V1\GetProductRequest;
use Google\Shopping\Merchant\Reports\V1\Client\ReportServiceClient;
use Google\Shopping\Merchant\Reports\V1\SearchRequest;
/**
* This class demonstrates how to get the list of all the disapproved products for a given merchant
* center account.
*/
class FilterDisapprovedProducts
{
/**
* Gets the product details for a given product using the GetProduct method.
*
* @param mixed $credentials The OAuth credentials.
* @param array $config The configuration data, including 'accountId'.
* @param string $productName The full resource name of the product to retrieve.
* Format: accounts/{account}/products/{product}
*/
private static function getProduct(
$credentials,
array $config,
string $productName
): void {
// Creates options config containing credentials for the client to use.
$options = ['credentials' => $credentials];
// Creates a ProductsServiceClient.
$productsServiceClient = new ProductsServiceClient($options);
// Calls the API and catches and prints any network failures/errors.
try {
// Construct the GetProductRequest.
// The name has the format: accounts/{account}/products/{productId}
$request = new GetProductRequest(['name' => $productName]);
// Make the API call.
$response = $productsServiceClient->getProduct($request);
// Prints the retrieved product.
// Protobuf messages are printed as JSON strings for readability.
print $response->serializeToJsonString() . "\n";
} catch (ApiException $e) {
// Prints any errors that occur during the API call.
printf("ApiException was thrown: %s\n", $e->getMessage());
}
}
/**
* Filters disapproved products for a given Merchant Center account using the Reporting API,
* then prints the details for each disapproved product.
*
* @param array $config The configuration data used for authentication and
* getting the account ID.
*/
public static function filterDisapprovedProductsSample(array $config): void
{
// Gets the OAuth credentials to make the request.
$credentials = Authentication::useServiceAccountOrTokenFile();
// Creates options config containing credentials for the Report client to use.
$reportClientOptions = ['credentials' => $credentials];
// Creates a ReportServiceClient.
$reportServiceClient = new ReportServiceClient($reportClientOptions);
// The parent resource name for the report.
// Format: accounts/{accountId}
$parent = sprintf("accounts/%s", $config['accountId']);
// The query to select disapproved products from the product_view.
// This query retrieves offer_id, id, title, and price for products
// that are 'NOT_ELIGIBLE_OR_DISAPPROVED'.
$query = "SELECT offer_id, id, title, price FROM product_view"
. " WHERE aggregated_reporting_context_status = 'NOT_ELIGIBLE_OR_DISAPPROVED'";
// Create the search report request.
$request = new SearchRequest([
'parent' => $parent,
'query' => $query
]);
print "Sending search report request for Product View.\n";
// Calls the Reports.search API method.
try {
$response = $reportServiceClient->search($request);
print "Received search reports response: \n";
// Iterates over all report rows in all pages.
// The client library automatically handles pagination.
foreach ($response->iterateAllElements() as $row) {
print "Printing data from Product View:\n";
// Prints the ReportRow object as a JSON string.
print $row->serializeToJsonString() . "\n";
// Get the full product resource name from the report row.
// The `id` field in ProductView is the product's full resource name.
// Format: `accounts/{account}/products/{product}`
$productName = $parent . "/products/" . $row->getProductView()->getId();
// OPTIONAL: Call getProduct to retrieve and print full product details.
// Pass the original credentials and config.
print "Getting full product details by calling GetProduct method:\n";
self::getProduct($credentials, $config, $productName);
}
} catch (ApiException $e) {
// Prints any errors that occur during the API call.
printf("ApiException was thrown: %s\n", $e->getMessage());
}
}
/**
* Helper to execute the sample.
*/
public function callSample(): void
{
$config = Config::generateConfig();
self::filterDisapprovedProductsSample($config);
}
}
// Run the script
$sample = new FilterDisapprovedProducts();
$sample->callSample();