NEW: OVME Case Study

Exploring Claude 3.5 Sonnet for Google Ads Optimizations – Testing RSA Analysis

 In Google Ads

Anthropic’s newest AI model Claude 3.5 Sonnet has received lots of positive feedback recently, especially in software and data circles, with people praising the AI’s ability to generate useful code quickly. 

At OpenMoves, we’ve continued to look for ways that AI can improve our work as media buyers and analysts, and we have lots of use cases for ChatGPT in our daily work. I decided to try Claude, and I thought of a test project: Let’s work on analyzing Google Responsive Search Ads, and trying to generate some optimizations and insights. 

As you may know, analyzing RSAs is challenging because Google does not report much detail on the specifics of headline and description performance, and the interface is a nuisance to use to get even the little data that Google does offer. 

As a test, I wanted a Google Ads script to export RSA performance details. This is not a novel concept, I’m sure there are lots of existing scripts to do this, but I started from scratch with Claude. 

Working with Claude to Make the Script

Here’s my initial prompt. Claude kicked out a script right away, but it took about 5 revisions between errors from Google and incorrect outputs into Google Sheets before the script really did what I wanted. 

However, after these revisions, the script worked great, and going back and forth with Claude to make the finished working script didn’t take very long. Overall it was impressive and the ability of AI models to write launchable code fast and basically free is likely to be a gamechanger in lots of industries. 

Claude is also good at making changes and corrections to the code – I asked for various revisions including changing how the data was returned, the columns used, and more, and the revisions it pushed back usually worked out of the box. 

Basically, Claude appears to be able to generate arbitrary Google Ads scripts for any use case you can think of, and edit them as you need, but you’ll need a little patience to go back and forth on making edits and debugging. 

Interpreting the Data: Claude vs. ChatGPT4o

With the script completed, I wanted to try to get some insights. My output file had a long list of headlines and descriptions, along with impression counts and a performance label. What can we do to learn from these labels and optimize? 

I dumped the raw performance report back to Claude and asked for insights. Strangely, it kicked back a completely wrong analysis, based on a data set for another business altogether. Perhaps it hallucinated this dataset, or more worryingly it misread it from another user! I was able to fix this by uploading a CSV rather than asking it to read a Google Sheet. The resulting analysis that came back was so-so in quality. It gave me suggestions but they were rather obvious. Perhaps with more time prompting I could have come up with something better. 

For comparison, I tried ChatGPT4o with the same prompt. Hilariously ChatGPT completely missed the point of the assignment initially, and gave me the suggestions below. Clearly these would not help someone trying to improve the ad performance. 

However once I improved my prompt, GPT’s analysis was better than Claude’s, with more specific insights on the data from the RSAs. GPT also seemed more comfortable with the large file size, which Claude complained about. Based on the data and analysis, I asked GPT and Claude to give me 10 headlines that would perform well. 

The output from GPT and Claude were both excellent. Subjectively I think Claude’s were a bit better. I also think providing the large dataset helped both come up with good headlines. The headlines provided were about as good as a human copywriter could do barring true brilliance, and the headlines were clearly informed by the data and analysis on which headlines performed best. 

If you’re interested, the Claude script for RSA generation is below. *Use at your own risk – this is raw AI outputted code with no QA or guarantee. Update the XXX variable with your own GSheet URL* 

function main() {

  const DAYS = 30;

  const spreadsheetUrl = “XXXXX”; // Replace with your Google Sheets URL

  const sheet = SpreadsheetApp.openByUrl(spreadsheetUrl).getActiveSheet();

  // Clear the existing content

  sheet.clear();

  // Set up the headers

  sheet.appendRow([

    “Campaign”, “Ad Group”, “Ad ID”, “Asset Type”, “Asset Text”, 

    “Performance Label”, “Impressions”, “Clicks”, “Cost”, “Conversions”, “Conv. Value”

  ]);

  const report = AdsApp.report(

    “SELECT campaign.name, ad_group.name, ad_group_ad.ad.id, ” +

    “asset.type, asset.text_asset.text, ” +

    “ad_group_ad_asset_view.performance_label, ” +

    “metrics.impressions, metrics.clicks, metrics.cost_micros, ” +

    “metrics.conversions, metrics.conversions_value ” +

    “FROM ad_group_ad_asset_view ” +

    “WHERE segments.date DURING LAST_” + DAYS + “_DAYS ” +

    “AND campaign.status = ‘ENABLED’ ” +

    “AND ad_group.status = ‘ENABLED’ ” +

    “AND ad_group_ad.status = ‘ENABLED’ ” +

    “AND ad_group_ad.ad.type = ‘RESPONSIVE_SEARCH_AD’ ” +

    “AND asset.type = ‘TEXT’ ” +

    “ORDER BY campaign.name, ad_group.name, ad_group_ad.ad.id”

  );

  const rows = report.rows();

  while (rows.hasNext()) {

    const row = rows.next();

    const assetText = row[‘asset.text_asset.text’];

    sheet.appendRow([

      row[‘campaign.name’],

      row[‘ad_group.name’],

      row[‘ad_group_ad.ad.id’],

      assetText.length <= 30 ? ‘Headline’ : ‘Description’, // Inferring asset type based on length

      assetText,

      row[‘ad_group_ad_asset_view.performance_label’],

      row[‘metrics.impressions’],

      row[‘metrics.clicks’],

      (parseFloat(row[‘metrics.cost_micros’]) / 1000000).toFixed(2), // Convert micros to currency

      row[‘metrics.conversions’],

      row[‘metrics.conversions_value’]

    ]);

  }

  Logger.log(“Report generated successfully. Check your Google Sheet.”);

}

Recent Posts