Does Google Ads Script support GA4

927 views
Skip to first unread message

Nick Harris

unread,
Jun 13, 2023, 10:24:06 AM6/13/23
to Google Ads Scripts Forum
Hi,

Does Google Ads Script support access to GA4 profiles?

Currently I query the Google Analytics API via Google Ads Script to get a report on recent activity:

var report = Analytics.Data.Ga.get(
          'ga:' + profileId,
          dateStartFormatted,  // Start date in yyyy-mm-dd format.
          dateEndFormatted,  // End date in yyyy-mm-dd format.          
          'ga:adClicks, ga:impressions, ga:CTR, ga:adCost, ga:transactions, ga:transactionRevenue, ga:sessions, ga:pageviews, ga:bounceRate, ga:avgTimeOnPage'
          , {              
              'dimensions': 'ga:campaign,ga:adGroup,ga:adwordsAdGroupID,ga:adwordsCreativeID,ga:adwordsCriteriaID',              
              'sort': '-ga:adCost',
              'filters': 'ga:adClicks>0'
          }
        );

I think I need to use the new API "Google Analytics Data API (GA4)", but this does not seem accessible from inside Google Ads Scripts.

I need to be able to get a similar report, but from the GA4 profile.

Can anyone advise the best approach to take please?

Thank you.

Nick

Sigurd Fabrin

unread,
Jun 14, 2023, 5:36:40 AM6/14/23
to Google Ads Scripts Forum
I experience the same problem. It seems that it's not supported in Google Ads scripts. Under 'Advanced APIs' there is only one Analytics and that is the old UA version

Quick workaround: You can connect to the new Google Analytics Data API with an app script in a Google sheet and from there, fetch the data into Google Ads and do your thing.


Sigurd

Nick Harris

unread,
Jun 14, 2023, 6:04:38 AM6/14/23
to Google Ads Scripts Forum
Thanks Sigurd. That's a good suggestion about using Google Sheets and Apps Script as a workaround.

Google Ads Scripts Forum Advisor

unread,
Jun 16, 2023, 9:50:46 AM6/16/23
to adwords...@googlegroups.com

Hi All,

 

Thank you for reaching out to the Google Ads Scripts Forum Channel.

 

@Sigurd - We appreciate your continued patronage to this community forum.

 

@Nick - Sigurd's response is a good direction to follow for a workaround. I can raise a feature request in order to check if it's feasible to expose the functionality within Google Ads Scripts, however, please do note that our team would be unable to provide a definite timeline with regard to it's release and would recommend you instead keep an eye on our Ads Developer Blog for future updates and latest announcements.

 

As an aside, would you be able to provide your Google Ads account ID as I would be relaying this with the request?

 

Relevant links:

 

This message is in relation to case "ref:_00D1U1174p._5004Q2mCU3Z:ref"

Thanks,
 
Google Logo Google Ads Scripts Team


Nick Harris

unread,
Jun 19, 2023, 4:26:09 AM6/19/23
to Google Ads Scripts Forum
Thanks for your response. 

I will keep an eye out on the Ads Developer Blog. I'm working with Google Ads account ID 386-997-5003.

Many thanks,


Nick

Google Ads Scripts Forum Advisor

unread,
Jun 21, 2023, 4:31:45 AM6/21/23
to adwords...@googlegroups.com

Hi Nick,

 

Thank you for providing this as well as for the confirmation. Please do let us know if we can assist you with anything else.

Nick Harris

unread,
Jun 21, 2023, 7:48:21 AM6/21/23
to Google Ads Scripts Forum
@Sigurd I've been working with Google Sheets and Apps Script like you suggested, but I can't seem to get the same data as displayed in GA4. The figures are not matching up. Did you experience anything like this?

I experience the same problem using the GA4 Query Explorer.

Thanks,


Nick
On Wednesday, 14 June 2023 at 10:36:40 UTC+1 Sigurd Fabrin wrote:

Sigurd Fabrin

unread,
Jun 21, 2023, 9:17:06 AM6/21/23
to Google Ads Scripts Forum
"The figures are not matching up. Did you experience anything like this?"
Yes, especially with data for the last few days. GA4 is much slower than UA to process data. And also, GA4 might do samlpling rather than performing a full query in the database.

You can get better data quality if you export the GA4 raw event data to bigQuery and query that database instead. You can set this up in GA4s admin settings.


Sigurd

Nick Harris

unread,
Jun 21, 2023, 5:56:07 PM6/21/23
to Google Ads Scripts Forum
I was worried you might say this. I will investigate to see if this meets my requirements.

Thanks again, it really helps.


Nick

Nick Harris

unread,
Jun 22, 2023, 5:06:59 PM6/22/23
to Google Ads Scripts Forum
I've had a bit of progress and I think I can avoid exporting the raw GA4 data to BigQuery.

Checking the GA4 Aquisition reports and trying to create the same report with an 'exploration' I realised I need to use the sessionGoogleAdsCampaignName dimension instead of googleAdsCampaignName. I then built the same query in  GA4 Query Explorer and the results returned matched GA4. I've run the same query via Apps Scripts in Google Sheets and seem to have the data I need. Comparing this data with the UA data for the same period I am only seeing slight differences, but I think that is to be expected.

This is the function I have created in Apps Script (based on the Analytics Data API  runReport sample code):

/**
 * Runs a report of a Google Analytics 4 property ID. Creates a sheet with the
 * report.
 */
function runReport() {
  /**
   * TODO(developer): Uncomment this variable and replace with your
   *   Google Analytics 4 property ID before running the sample.
   */
  const propertyId = 'XXXXXX'

  try {
   
    // create the request
    const request = AnalyticsData.newRunReportRequest();
   
    request.dimensions = [
       
        { "name": "date" },

        // { "name": "googleAdsCampaignName" }
        //,{ "name": "googleAdsAdGroupName" }
        //,{ "name": "googleAdsAdGroupId" }
        //,{ "name": "googleAdsCreativeId" }

         { "name": "sessionGoogleAdsCampaignName" }
        ,{ "name": "sessionGoogleAdsAdGroupName" }
        ,{ "name": "sessionGoogleAdsAdGroupId" }
        ,{ "name": "sessionGoogleAdsCreativeId" }

       
      ];    
   
    request.metrics = [        
         { "name": "advertiserAdClicks" }
        ,{ "name": "advertiserAdImpressions" }
       
        // no match found for ga:CTR       
        ,{ "name": "advertiserAdCost" }
       
        ,{ "name": "transactions" }       

        ,{ "name": "totalRevenue" }
        ,{ "name": "sessions" }
        ,{ "name": "screenPageViews" }
        ,{ "name": "bounceRate" }
        ,{ "name": "averageSessionDuration" }                  

      ];
    request.dateRanges = [
        {
           "startDate": "yesterday" //"yesterday" "2023-06-19"
          ,"endDate": "yesterday"   //"yesterday"
        }
      ];

      request.limit = 1000;

    // ignore where campaign or ad group not set    
    request.dimensionFilter = {"andGroup":{"expressions":[{"notExpression":{"filter":{"stringFilter":{"value":"(not set)","caseSensitive":false,"matchType":"EXACT"},"fieldName":"sessionGoogleAdsCampaignName"}}},{"notExpression":{"filter":{"stringFilter":{"value":"(not set)","caseSensitive":false,"matchType":"EXACT"},"fieldName":"sessionGoogleAdsAdGroupName"}}}
    //,{"filter":{"fieldName":"sessionGoogleAdsCampaignName","stringFilter":{"matchType":"BEGINS_WITH","value":"Shopping","caseSensitive":false}}}    
    ]}};

    // only where clicks > 0
    request.metricFilter = {"filter":{"fieldName":"advertiserAdClicks","numericFilter":{"operation":"GREATER_THAN","value":{"doubleValue":"0"}}}};


    request.orderBys = [{"metric":{"metricName":"advertiserAdCost"},"desc":true}];
   
    request.keepEmptyRows = true;

    //request.metricAggregations = "";

    const report = AnalyticsData.Properties.runReport(request, 'properties/' + propertyId);

   
    if (!report.rows) {
      console.log('No rows returned.');
      return;
    }

    //const spreadsheet = SpreadsheetApp.create('Google Analytics Report');
    // load the linked spreadsheet
    const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();// ( ('Google Analytics Report');
    const sheet = spreadsheet.getSheetByName('Analytics');
    sheet.clear();


    // Append the headers.
    const dimensionHeaders = report.dimensionHeaders.map(
        (dimensionHeader) => {
          return dimensionHeader.name;
        });
    const metricHeaders = report.metricHeaders.map(
        (metricHeader) => {
          return metricHeader.name;
        });
    const headers = [...dimensionHeaders, ...metricHeaders];

    sheet.appendRow(headers);

    // Append the results.
    const rows = report.rows.map((row) => {
      const dimensionValues = row.dimensionValues.map(
          (dimensionValue) => {
            return dimensionValue.value;
          });
      const metricValues = row.metricValues.map(
          (metricValues) => {
            return metricValues.value;
          });
      return [...dimensionValues, ...metricValues];
    });

    sheet.getRange(2, 1, report.rows.length, headers.length)
        .setValues(rows);

    console.log('Report spreadsheet created: %s',
        spreadsheet.getUrl());

  } catch (e) {
    // TODO (Developer) - Handle exception
    console.log('Failed with error: %s', e.error);

    // throw full error when testing so we can see more detail
    throw e;
  }

}

Scott Mulder

unread,
Dec 19, 2023, 3:41:14 AM12/19/23
to Google Ads Scripts Forum
Google team,

It seems that since you forced us all onto GA4 you would also have worked the solution into ads scripting to allow access to the old data. 
The question above was asked in June and it is now December.
When can we expect AnalyticsData to be exposed into ads scripts?

Thanks tons, 
Scott

Reply all
Reply to author
Forward
0 new messages