Created
June 16, 2025 12:49
-
-
Save jrosell/4a24f717850fe04ddeb2173bfd39a3ec to your computer and use it in GitHub Desktop.
Script in Google Ads account to export data to a Google Sheets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function main() { | |
var spreadsheetUrl = 'https://docs.google.com/spreadsheets/d/id/edit?usp=sharing'; | |
var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetUrl); | |
var pivotedSheet = getOrCreateSheet(spreadsheet, 'PivotedConversionActions'); // New pivoted data sheet | |
var firstDate = '2022-01-01'; | |
var startDate = getDateNDaysAgo(200); | |
var endDate = getDateNDaysAgo(1); | |
// Step 1: Fetch conversion action names | |
var conversionActionNames = getConversionActionNames(firstDate, endDate); | |
// Step 2: Fetch conversion actions data | |
var conversionQuery = ` | |
SELECT | |
segments.date, | |
segments.week, | |
segments.month, | |
campaign.status, | |
campaign.name, | |
customer.currency_code, | |
campaign.advertising_channel_type, | |
segments.conversion_action_name, | |
metrics.conversions | |
FROM campaign | |
WHERE segments.date BETWEEN '${startDate}' AND '${endDate}' AND | |
customer.currency_code = "EUR" | |
`; | |
var conversionData = fetchData(conversionQuery); | |
// Step 3: Fetch campaign data | |
var campaignQuery = ` | |
SELECT | |
segments.date, | |
segments.week, | |
segments.month, | |
campaign.status, | |
campaign.name, | |
customer.currency_code, | |
campaign.advertising_channel_type, | |
metrics.clicks, | |
metrics.impressions, | |
metrics.cost_micros, | |
metrics.conversions, | |
metrics.conversions_value | |
FROM campaign | |
WHERE segments.date BETWEEN '${startDate}' AND '${endDate}' AND | |
customer.currency_code = "EUR" | |
`; | |
var campaignData = fetchData(campaignQuery); | |
// Step 4: Pivot conversion actions and store the data in a new sheet | |
var pivotedData = pivotConversionActions(campaignData, conversionData, conversionActionNames); | |
// Step 5: Store the pivoted data in the PivotedConversionActions sheet | |
storePivotedData(pivotedData, pivotedSheet); | |
} | |
// Function to fetch conversion action names | |
function getConversionActionNames(startDate, endDate) { | |
var conversionActionQuery = ` | |
SELECT | |
segments.date, | |
segments.conversion_action_name | |
FROM campaign | |
WHERE segments.date BETWEEN '${startDate}' AND '${endDate}' | |
ORDER BY segments.date ASC | |
`; | |
var conversionActionData = fetchData(conversionActionQuery); | |
var conversionActionOrder = {}; | |
var orderedConversionActionNames = []; | |
conversionActionData.forEach(function(row) { | |
var actionName = String(row[1]).trim(); // Ensure clean names | |
if (!(actionName in conversionActionOrder)) { | |
conversionActionOrder[actionName] = orderedConversionActionNames.length; | |
orderedConversionActionNames.push(actionName); | |
} | |
}); | |
Logger.log("Ordered Conversion Action Names: " + orderedConversionActionNames); | |
return orderedConversionActionNames; | |
} | |
// Function to fetch data | |
function fetchData(query) { | |
var report = AdsApp.report(query); | |
var rows = report.rows(); | |
var data = []; | |
while (rows.hasNext()) { | |
var row = rows.next(); | |
var rowData = Object.values(row); | |
rowData = rowData.filter(value => typeof value !== 'function'); | |
if (rowData.length > 0) { | |
data.push(rowData); | |
} | |
} | |
return data; | |
} | |
// Pivot conversion actions and merge with campaign data | |
function pivotConversionActions(campaignData, conversionData, conversionActionNames) { | |
var pivotedData = []; | |
// Define headers | |
var headers = [ | |
'Day', 'Week', 'Month', 'Status', 'Campaign', 'Currency', 'Campaign type', | |
'SUM of Clicks', 'SUM of Impr.', 'SUM of Cost', 'SUM of Conversions', 'SUM of Conv. value' | |
].concat(conversionActionNames); | |
pivotedData.push(headers); | |
// Create lookup table for campaign data | |
var campaignMap = {}; | |
campaignData.forEach(function(row) { | |
var key = row.slice(0, 7).map(val => String(val).trim()).join('|'); // 0-7: row[0]...row[6] | |
var baseRow = [ | |
row[0], // Date | |
row[1], // Week | |
row[2], // Month | |
row[3], // Status | |
row[4], // Campaign Name | |
row[5], // Currency | |
row[6], // Advertising Channel Type | |
row[7], // Clicks | |
row[8], // Impressions | |
row[9] / 1000000, // Cost | |
row[10], // Conversions | |
row[11], // Conversion Value | |
]; | |
var conversionCounts = Array(conversionActionNames.length).fill(0); | |
campaignMap[key] = baseRow.concat(conversionCounts); | |
}); | |
Logger.log("✅ Campaign Keys Count: " + Object.keys(campaignMap).length); | |
// Populate pivoted conversion values | |
var missingKeys = 0; | |
conversionData.forEach(function(row) { | |
var key = row.slice(0, 7).map(val => String(val).trim()).join('|'); // 0-7: row[0]...row[6] | |
var conversionAction = String(row[7]).trim(); | |
var conversionIndex = conversionActionNames.indexOf(conversionAction); | |
if (campaignMap[key] && conversionIndex !== -1) { | |
var columnIndex = 12 + conversionIndex; | |
campaignMap[key][columnIndex] += parseFloat(row[8]) || 0; | |
} else { | |
Logger.log(`⚠️ Missing Key: ${key} | Conversion Action: ${conversionAction}`); | |
missingKeys++; | |
} | |
}); | |
Logger.log(`⚠️ Total Missing Keys: ${missingKeys}`); | |
// Store pivoted rows | |
Object.values(campaignMap).forEach(function(rowData) { | |
while (rowData.length < headers.length) { | |
rowData.push(0); | |
} | |
while (rowData.length > headers.length) { | |
rowData.pop(); | |
} | |
pivotedData.push(rowData); | |
}); | |
Logger.log("✅ Final Pivoted Data Length: " + pivotedData.length); | |
return pivotedData; | |
} | |
// Store data in Google Sheets | |
function storePivotedData(data, sheet) { | |
if (data.length > 0) { | |
sheet.clear(); | |
var numColumns = data[0].length; | |
Logger.log("📊 Expected Columns (Headers): " + numColumns); | |
// Check if all data rows have the correct number of columns | |
data.forEach((row, index) => { | |
if (row.length !== numColumns) { | |
Logger.log(`⚠️ Row ${index} has ${row.length} columns (Expected: ${numColumns})`); | |
Logger.log("➡️ Row Data: " + row); | |
} | |
}); | |
try { | |
sheet.getRange(1, 1, data.length, numColumns).setValues(data); | |
} catch (e) { | |
Logger.log("🚨 Error when setting values: " + e.message); | |
Logger.log("⚠️ ERROR: Column count mismatch!"); | |
throw e; | |
} | |
} | |
} | |
// Get or create a Google Sheet | |
function getOrCreateSheet(spreadsheet, sheetName) { | |
var sheet = spreadsheet.getSheetByName(sheetName); | |
if (!sheet) { | |
sheet = spreadsheet.insertSheet(sheetName); | |
} | |
return sheet; | |
} | |
// Get date N days ago | |
function getDateNDaysAgo(n) { | |
var date = new Date(); | |
date.setDate(date.getDate() - n); | |
var timeZone = AdsApp.currentAccount().getTimeZone(); | |
return Utilities.formatDate(date, timeZone, 'yyyy-MM-dd'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment