I have tried implementing the below script to get MCC Account Anomaly Detection for the last 30 days vs pervious 30 days absolute change and % of changes in the specific metrics including Impressions, Clicks, Conversions & Cost. However, this script is not running at all. it would be great. if i can get immediate assistance to correct this script and get objective fulfilled.
/**
* Configuration to be used for the Account Performance Comparator.
*/
CONFIG = {
// URL of the default spreadsheet template. Make sure the sheet is owned by or shared with the same Google user executing the script.
'spreadsheet_url': '
https://docs.google.com/spreadsheets/d/183GMf9qvzoV0O2b7be1JsNxNshyhkf-CwUwnN1MJDoM/edit?gid=0#gid=0',
'mcc_child_account_limit': 100,
// Reporting API version
'reporting_options': {
'apiVersion': 'v17'
},
// Alert thresholds for anomalies
'alert_threshold': {
'clicks': 50, // Example threshold; adjust as needed
'impressions': 100,
'cost': 1000
}
};
function main() {
const spreadsheet = SpreadsheetApp.openByUrl(CONFIG.spreadsheet_url);
let sheet = spreadsheet.getSheetByName('PerformanceData');
// Create or clear the 'PerformanceData' sheet
if (!sheet) {
sheet = spreadsheet.insertSheet('PerformanceData');
} else {
sheet.clear();
}
// Set headers
const headers = [
'MCC Account ID', 'Account ID', 'Account Name', 'Clicks', 'Impressions',
'Conversions', 'Cost', 'Last 30 Days', 'Previous 30 Days', 'Absolute Change', 'Alert'
];
sheet.appendRow(headers);
const accountIterator = AdsManagerApp.accounts().withLimit(CONFIG.mcc_child_account_limit).get();
while (accountIterator.hasNext()) {
const account = accountIterator.next();
AdsManagerApp.select(account);
// Fetch data for last 30 days and previous 30 days
const last30Days = fetchPerformanceData("LAST_30_DAYS");
const prev30Days = fetchPerformanceData("PREVIOUS_30_DAYS");
// Calculate percentage and absolute changes
const changes = calculatePercentageChanges(last30Days, prev30Days);
const absoluteChanges = calculateAbsoluteChanges(last30Days, prev30Days);
// Determine alerts based on thresholds
const alert = generateAlert(changes, absoluteChanges);
// Append data to the spreadsheet
sheet.appendRow([
AdsApp.currentAccount().getCustomerId(),
account.getCustomerId(),
account.getName(),
changes.clicks,
changes.impressions,
changes.conversions,
changes.cost,
JSON.stringify(last30Days),
JSON.stringify(prev30Days),
JSON.stringify(absoluteChanges),
alert
]);
}
Logger.log('Performance data updated in spreadsheet.');
}
/**
* Fetch performance data for the specified date range.
*/
function fetchPerformanceData(dateRange) {
const query = `
SELECT
metrics.impressions,
metrics.clicks,
metrics.conversions,
metrics.cost_micros
FROM campaign
WHERE metrics.impressions > 0
DURING ${dateRange}
`;
const report = AdsApp.report(query);
const rows = report.rows();
let data = {
impressions: 0,
clicks: 0,
conversions: 0,
cost: 0
};
while (rows.hasNext()) {
const row = rows.next();
data.impressions += parseFloat(row['metrics.impressions']);
data.clicks += parseFloat(row['metrics.clicks']);
data.conversions += parseFloat(row['metrics.conversions']);
data.cost += parseFloat(row['metrics.cost_micros']) / 1e6; // Convert micros to standard currency
}
return data;
}
/**
* Calculate percentage changes between two periods.
*/
function calculatePercentageChanges(current, previous) {
const calculateChange = (current, previous) => {
return previous === 0 ? (current > 0 ? 100 : 0) : ((current - previous) / previous) * 100;
};
return {
impressions: calculateChange(current.impressions, previous.impressions).toFixed(2),
clicks: calculateChange(current.clicks, previous.clicks).toFixed(2),
conversions: calculateChange(current.conversions, previous.conversions).toFixed(2),
cost: calculateChange(current.cost, previous.cost).toFixed(2)
};
}
/**
* Calculate absolute changes between two periods.
*/
function calculateAbsoluteChanges(current, previous) {
return {
impressions: Math.abs(current.impressions - previous.impressions),
clicks: Math.abs(current.clicks - previous.clicks),
conversions: Math.abs(current.conversions - previous.conversions),
cost: Math.abs(current.cost - previous.cost)
};
}
/**
* Generate alerts based on thresholds.
*/
function generateAlert(changes, absoluteChanges) {
const alertMessages = [];
if (changes.clicks > CONFIG.alert_threshold.clicks) {
alertMessages.push('Clicks anomaly');
}
if (changes.impressions > CONFIG.alert_threshold.impressions) {
alertMessages.push('Impressions anomaly');
}
if (absoluteChanges.cost > CONFIG.alert_threshold.cost) {
alertMessages.push('Cost anomaly');
}
return alertMessages.join(', ');
}
Awaiting quick response.