Advertisement
Marc_Cornelius

Google Ads // Change History MCC Account Level Script

Aug 7th, 2024
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.90 KB | None | 0 0
  1. /**
  2. * Google Ads Unauthorized Change Detector
  3. *
  4. * N00b Instructions:
  5. * 1. This script is for Google Ads and runs in the Google Ads Scripts interface.
  6. * 2. You need to have MCC (Manager Account) level access to use this script.
  7. * 3. Before using, you need to set up a few things:
  8. * a. Create a new Google Sheet to store the change logs.
  9. * b. Copy the URL of this sheet and paste it in the CONFIG.spreadsheetUrl below.
  10. * c. List the email addresses that should receive alerts in CONFIG.emailRecipients.
  11. * d. In CONFIG.trustedUsers, list the email addresses of users whose changes should not trigger alerts.
  12. * 4. To set up the script in Google Ads:
  13. * a. In your MCC account, go to Tools & Settings > Bulk Actions > Scripts.
  14. * b. Click the big blue "+" button to create a new script.
  15. * c. Give your script a name (e.g., "Unauthorized Change Detector").
  16. * d. Copy and paste this entire script into the editor.
  17. * e. Click "Save" and then "Preview" to test the script.
  18. * f. If everything looks good, click "Run" to execute the script.
  19. * 5. To run this script regularly:
  20. * a. After saving, click on "Create schedule" in the scripts interface.
  21. * b. Choose how often you want the script to run (daily is recommended).
  22. * c. Select a time for the script to run.
  23. * d. Click "Submit" to schedule the script.
  24. *
  25. * If you encounter any errors or have questions, consult the Google Ads Scripts documentation
  26. * or seek help from a more experienced user or the Google Ads support team.
  27. */
  28.  
  29. // Global configuration
  30. const CONFIG = {
  31. spreadsheetUrl: '[SPREADSHEET URL]', // Replace with your Google Sheet URL
  32. emailRecipients: '[EMAIL ADDRESS LIST]', // Replace with comma-separated email addresses
  33. trustedUsers: ['[USER1]', '[USER2]', '[USER3]'], // Replace with trusted user email addresses
  34. emailSubject: 'Alert: Unauthorized Google Ads Changes Detected',
  35. timeRange: 'YESTERDAY',
  36. enableEmailAlerts: true
  37. };
  38.  
  39. // Main execution function
  40. function executeAudit() {
  41. const accountIterator = AdsManagerApp.accounts().get();
  42. while (accountIterator.hasNext()) {
  43. const account = accountIterator.next();
  44. AdsManagerApp.select(account);
  45. auditAccount();
  46. }
  47. }
  48.  
  49. // Audit individual account
  50. function auditAccount() {
  51. const accountName = AdsApp.currentAccount().getName();
  52. Logger.log(`Auditing account: ${accountName}`);
  53.  
  54. const unauthorizedChanges = fetchUnauthorizedChanges();
  55.  
  56. if (unauthorizedChanges.length > 0) {
  57. logChangesToSpreadsheet(unauthorizedChanges);
  58. if (CONFIG.enableEmailAlerts) {
  59. notifyViaEmail(unauthorizedChanges.length, accountName);
  60. }
  61. } else {
  62. Logger.log('No unauthorized changes detected');
  63. recordNoChangesFound();
  64. }
  65. }
  66.  
  67. // Fetch unauthorized changes
  68. function fetchUnauthorizedChanges() {
  69. const query = buildChangeQuery();
  70. const result = AdsApp.search(query);
  71. const changes = [];
  72.  
  73. while (result.hasNext()) {
  74. const row = result.next();
  75. const change = extractChangeInfo(row);
  76. if (change) changes.push(change);
  77. }
  78.  
  79. return changes;
  80. }
  81.  
  82. // Build AWQL query
  83. function buildChangeQuery() {
  84. const fields = [
  85. 'campaign.name', 'ad_group.name', 'change_event.change_date_time',
  86. 'change_event.change_resource_type', 'change_event.changed_fields',
  87. 'change_event.client_type', 'change_event.feed', 'change_event.feed_item',
  88. 'change_event.new_resource', 'change_event.old_resource',
  89. 'change_event.resource_change_operation', 'change_event.resource_name',
  90. 'change_event.user_email'
  91. ];
  92.  
  93. return `SELECT ${fields.join(', ')} FROM change_event
  94. WHERE change_event.change_date_time DURING ${CONFIG.timeRange}
  95. AND change_event.user_email NOT IN ('${CONFIG.trustedUsers.join("', '")}')
  96. ORDER BY change_event.change_date_time DESC
  97. LIMIT 9999`;
  98. }
  99.  
  100. // Extract change information
  101. function extractChangeInfo(row) {
  102. try {
  103. return [
  104. row.changeEvent.changeDateTime,
  105. AdsApp.currentAccount().getName(),
  106. row.changeEvent.userEmail,
  107. row.changeEvent.clientType,
  108. row.campaign ? row.campaign.name : '',
  109. row.adGroup ? row.adGroup.name : '',
  110. row.changeEvent.changeResourceType,
  111. row.changeEvent.changedFields,
  112. row.changeEvent.feed,
  113. row.changeEvent.feedItem,
  114. row.changeEvent.newResource,
  115. row.changeEvent.oldResource,
  116. row.changeEvent.resourceChangeOperation
  117. ];
  118. } catch (error) {
  119. Logger.log(`Error extracting change info: ${error}`);
  120. return null;
  121. }
  122. }
  123.  
  124. // Log changes to spreadsheet
  125. function logChangesToSpreadsheet(changes) {
  126. const sheet = SpreadsheetApp.openByUrl(CONFIG.spreadsheetUrl).getActiveSheet();
  127. if (sheet.getLastRow() === 0) {
  128. sheet.appendRow([
  129. 'Date', 'Account', 'User', 'Client Type', 'Campaign', 'Ad Group',
  130. 'Change Type', 'Changed Fields', 'Feed', 'Feed Item', 'New Resource',
  131. 'Old Resource', 'Change Operation'
  132. ]);
  133. }
  134. sheet.insertRowsBefore(2, changes.length);
  135. sheet.getRange(2, 1, changes.length, changes[0].length).setValues(changes);
  136. }
  137.  
  138. // Record when no changes are found
  139. function recordNoChangesFound() {
  140. const sheet = SpreadsheetApp.openByUrl(CONFIG.spreadsheetUrl).getActiveSheet();
  141. const today = new Date();
  142. sheet.appendRow([
  143. Utilities.formatDate(today, AdsApp.currentAccount().getTimeZone(), 'yyyy-MM-dd'),
  144. 'No unauthorized changes detected'
  145. ]);
  146. }
  147.  
  148. // Send email notification
  149. function notifyViaEmail(changeCount, accountName) {
  150. const body = `
  151. ${changeCount} unauthorized change(s) detected in account: ${accountName}
  152. Details available at: ${CONFIG.spreadsheetUrl}
  153.  
  154. This audit covers changes made ${CONFIG.timeRange}.
  155. Trusted users: ${CONFIG.trustedUsers.join(', ')}
  156. `;
  157.  
  158. MailApp.sendEmail(CONFIG.emailRecipients, CONFIG.emailSubject, body);
  159. Logger.log('Email alert sent');
  160. }
  161.  
  162. // Execute the script
  163. executeAudit();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement