By default, in Google Merchant Center, there is no way to use Pmax performance data; while Google does show the data in your reports, it does not show the data at the product level. By having PMax data on a per-product level, you can, for example, split your campaigns up between best-performing and low-performing campaigns, using feed rules and applying custom labels. Then, create campaigns based on these labels.
This can be done by utilizing the script and plugin below, which generates data in a spreadsheet which can be used as a supplement feed.
This script was made possible by looking at the code Jermaya Leijen created, where the original inspiration came from Frederick Vallaeys. So, these two deserve enormous credit.
I also have a paid version of this script that allows you to pull and merge data from multiple campaigns. Allowing you to setup even more advanced campaigns. Feel free to reach out for more info.
Change the campaignName and add your empty sheetUrl using the script below. Then, plug the spreadsheet data as a supplemental feed into Google Merchant Center.
/****************************
* Original Inspiration By (smart shopping): Frederick Vallaeys : https://gist.github.com/siliconvallaeys/87be58bcb9ddd741fbf743359578dc60
* Inspired By (pmax): Jermaya Leijen : Script: https://adsscripts.com/scripts/google-ads-scripts/pmax-data
* Modified by: FeedArmy (https://feedarmy.com) V1.01
* The inspiration is based on when I first used a code, there may be many other developers with similar ideas
* The code I modified is pretty much 90% modified
****************************/
function main() {
try {
// Constants
const countDays = 30;
const sheetUrl = "https://docs.google.com/spreadsheets/d/1hB42Xd9ZqMvFm5YqMhc2EaTfHTpnHxqhzB_-pGAhwOM/copy";
const campaignName = "US - Performance Max";
const end = new Date(Date.now() - 86400000);
const start = new Date(Date.now() - countDays * 86400000);
const searchQuery = `SELECT segments.product_item_id, campaign.id, campaign.name, campaign.advertising_channel_type, metrics.conversions, metrics.conversions_value, metrics.clicks, metrics.cost_micros, metrics.impressions FROM shopping_performance_view WHERE campaign.advertising_channel_type = PERFORMANCE_MAX AND campaign.name = "${campaignName}" AND segments.date>='${dateFormat(start)}' AND segments.date <='${dateFormat(end)}' `;
// Data array initialization
let data = [["id", "impressions", "clicks", "conversions", "conversion_value", "cost", "roas"]];
// Google Sheets
const ss = SpreadsheetApp.openByUrl(sheetUrl);
let sh = ss.getSheetByName("Sheet1");
// Clear existing data if any
if (sh.getMaxRows() > 1) sh.getRange(1, 1, sh.getMaxRows(), data[0].length).clear();
// Fetch search results
let searchResults = AdsApp.search(searchQuery);
// Process search results
for (const row of searchResults) {
let cost = row.metrics.costMicros / 1000000;
let roas = (row.metrics.conversionsValue / cost).toFixed(2);
// Check if ROAS is NaN, set it to zero
if (isNaN(roas)) {
roas = 0;
}
let productId = row.segments.productItemId;
// Handle product ID
if (productId.includes("shopify")) {
let countryCode = productId.slice(8, 10);
let productIdVariantId = productId.substring(productId.indexOf(countryCode) + 2);
productId = "shopify_" + countryCode.toUpperCase() + productIdVariantId;
}
// Push data to array
data.push([productId, row.metrics.impressions, row.metrics.clicks, row.metrics.conversions, row.metrics.conversionsValue, cost.toFixed(2), roas]);
}
// Write data to Google Sheets
sh.getRange(1, 1, data.length, data[0].length).setValues(data);
} catch (error) {
Logger.log("An error occurred: " + error.toString());
}
}
function dateFormat(date) {
return Utilities.formatDate(date, AdsApp.currentAccount().getTimeZone(), 'yyyy-MM-dd');
}