Setup Advanced PMax Campaigns Using Performance Data

Setup Advanced PMax Campaigns Using Performance Data

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');
  }

Need Help?
Do you have a question or need specialist support? Get in touch!

Subscribe
Notify of
guest
5 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Felix
Felix
6 days ago

Hi Emmanuel. What might be causing that only the roas column has data from row 30 and beyond? I’m running 2 pmax campaigns (best performers and low performers). I’ve installed the script for each campaign, but many id fields were blank, so I’ve also tested running the script only for the best performers, but still many ID fields are blank. Also, a feed rule for custom label 2 sets the value to ‘under kpi’ for any product under 5x ROAS from both supplemental feeds (1 per pmax) as you show above. Any help is much appreciated, thanks in advance.

Felix Mayo Sanchez
Felix Mayo Sanchez
1 month ago

When uploading the supplemental feed, I receive the following issue Global feed issues>File Not Found> Failed to locate file. Please make sure the file exists.
Thanks for the resource and help Emmanuel.

5
0
Would love your thoughts, please comment.x
()
x