What This Script Does
This script generates a detailed spreadsheet report containing all key components of your Google Ads campaigns created within the last 30 days. It organizes the data into separate sheets for campaigns, ad groups, ads, keywords, and extensions, making it easier to analyze your account structure and performance.
function main() {
var spreadsheet = SpreadsheetApp.create("Comprehensive Campaign Details (Last 30 Days)");
var campaignSheet = spreadsheet.getActiveSheet().setName("Campaigns");
var adGroupSheet = spreadsheet.insertSheet("Ad Groups");
var adSheet = spreadsheet.insertSheet("Ads");
var keywordSheet = spreadsheet.insertSheet("Keywords");
var extensionSheet = spreadsheet.insertSheet("Extensions");
var thirtyDaysAgo = getDateString(30);
var relevantCampaignIds = fetchCampaigns(campaignSheet, thirtyDaysAgo);
fetchAdGroups(adGroupSheet, relevantCampaignIds);
fetchAds(adSheet, relevantCampaignIds);
fetchKeywords(keywordSheet, relevantCampaignIds);
fetchExtensions(extensionSheet, thirtyDaysAgo);
Logger.log("Report generated: " + spreadsheet.getUrl());
}
function getDateString(daysAgo) {
var date = new Date();
date.setDate(date.getDate() - daysAgo);
return Utilities.formatDate(date, "GMT", "yyyyMMdd");
}
function fetchCampaigns(sheet, startDate) {
sheet.appendRow([
"Campaign ID", "Campaign Name", "Status", "Type", "Daily Budget",
"Bidding Strategy", "Start Date", "End Date", "Targeted Locations",
"Excluded Locations", "Languages"
]);
var relevantCampaignIds = [];
var campaignIterator = AdsApp.campaigns()
.withCondition("StartDate >= '" + startDate + "'")
.get();
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var targetedLocations = getLocationNames(campaign.targeting().targetedLocations());
var excludedLocations = getLocationNames(campaign.targeting().excludedLocations());
var languages = getLanguageNames(campaign.targeting().languages());
sheet.appendRow([
campaign.getId(),
campaign.getName(),
campaign.isEnabled() ? "ENABLED" : "PAUSED",
campaign.getAdvertisingChannelType(),
campaign.getBudget().getAmount().toFixed(2),
campaign.getBiddingStrategyType(),
campaign.getStartDate(),
campaign.getEndDate() || "No end date",
targetedLocations,
excludedLocations,
languages
]);
relevantCampaignIds.push(campaign.getId());
}
return relevantCampaignIds;
}
function getLocationNames(locationSelector) {
// ... (no changes needed here)
}
function getLanguageNames(languageSelector) {
// ... (no changes needed here)
}
function fetchAdGroups(sheet, relevantCampaignIds) {
sheet.appendRow([
"Campaign ID", "Campaign Name", "Ad Group ID", "Ad Group Name",
"Status"
]);
var adGroupIterator = AdsApp.adGroups()
.withCondition("CampaignId IN [" + relevantCampaignIds.join(",") + "]")
.get();
while (adGroupIterator.hasNext()) {
var adGroup = adGroupIterator.next();
var campaign = adGroup.getCampaign();
sheet.appendRow([
campaign.getId(),
campaign.getName(),
adGroup.getId(),
adGroup.getName(),
adGroup.isEnabled() ? "ENABLED" : "PAUSED"
]);
}
}
function fetchAds(sheet, relevantCampaignIds) {
var headers = [
"Campaign ID", "Campaign Name", "Ad Group ID", "Ad Group Name",
"Ad ID", "Ad Type"
];
for (var i = 1; i <= 15; i++) {
headers.push("Headline " + i);
}
for (var i = 1; i <= 4; i++) {
headers.push("Description " + i);
}
headers.push("Final URL");
sheet.appendRow(headers);
var adIterator = AdsApp.ads()
.withCondition("CampaignId IN [" + relevantCampaignIds.join(",") + "]")
.get();
while (adIterator.hasNext()) {
var ad = adIterator.next();
var adGroup = ad.getAdGroup();
var campaign = adGroup.getCampaign();
var row = [
campaign.getId(),
campaign.getName(),
adGroup.getId(),
adGroup.getName(),
ad.getId(),
ad.getType()
];
var headlines = [];
var descriptions = [];
try {
headlines = ad.getHeadlines ? ad.getHeadlines() : [];
descriptions = ad.getDescriptions ? ad.getDescriptions() : [];
} catch (e) {
// If getHeadlines or getDescriptions are not available, we'll have empty arrays
}
for (var i = 0; i < 15; i++) {
row.push(headlines[i] || "N/A");
}
for (var i = 0; i < 4; i++) {
row.push(descriptions[i] || "N/A");
}
var finalUrl = "N/A";
try {
finalUrl = ad.urls().getFinalUrl() || "N/A";
} catch (e) {
// If getFinalUrl is not available, we'll use "N/A"
}
row.push(finalUrl);
sheet.appendRow(row);
}
}
function fetchKeywords(sheet, relevantCampaignIds) {
sheet.appendRow([
"Campaign ID", "Campaign Name", "Ad Group ID", "Ad Group Name",
"Keyword ID", "Keyword Text", "Match Type", "Status"
]);
var keywordIterator = AdsApp.keywords()
.withCondition("CampaignId IN [" + relevantCampaignIds.join(",") + "]")
.get();
while (keywordIterator.hasNext()) {
var keyword = keywordIterator.next();
var adGroup = keyword.getAdGroup();
var campaign = adGroup.getCampaign();
sheet.appendRow([
campaign.getId(),
campaign.getName(),
adGroup.getId(),
adGroup.getName(),
keyword.getId(),
keyword.getText(),
keyword.getMatchType(),
keyword.isEnabled() ? "ENABLED" : "PAUSED"
]);
}
}
function fetchExtensions(sheet, startDate) {
// ... (no changes needed here)
}
function fetchSitelinkExtensions(sheet, startDate) {
// ... (no changes needed here)
}
function fetchCalloutExtensions(sheet, startDate) {
// ... (no changes needed here)
}
Script Output
Campaigns Sheet
Campaign ID | Campaign Name | Status | Type | Daily Budget | Bidding Strategy | Start Date | End Date | Targeted Locations | Excluded Locations | Languages |
---|---|---|---|---|---|---|---|---|---|---|
1234567890 | Summer Promotion | ENABLED | SEARCH | 50 | MAXIMIZE_CONVERSIONS | 20250420 | No end date | United States, Canada | Mexico | English, French |
2345678901 | Brand Campaign | ENABLED | SEARCH | 35 | MANUAL_CPC | 20250422 | 20250630 | United Kingdom, Germany | Russia | English, German |
3456789012 | Display Remarketing | PAUSED | DISPLAY | 25 | TARGET_ROAS | 20250425 | No end date | Global | China | All |
Ad Groups Sheet
Campaign ID | Campaign Name | Ad Group ID | Ad Group Name | Status |
---|---|---|---|---|
1234567890 | Summer Promotion | 11223344 | Women’s Clothing | ENABLED |
1234567890 | Summer Promotion | 22334455 | Men’s Apparel | ENABLED |
2345678901 | Brand Campaign | 33445566 | Brand Terms | ENABLED |
Ads Sheet
Campaign ID | Campaign Name | Ad Group ID | Ad Group Name | Ad ID | Ad Type | Headline 1 | Headline 2 | Description 1 | Final URL |
---|---|---|---|---|---|---|---|---|---|
1234567890 | Summer Promotion | 11223344 | Women’s Clothing | 123456 | RESPONSIVE_SEARCH_AD | Summer Sale | 50% Off | Shop our latest collection | https://example.com/womens |
2345678901 | Brand Campaign | 33445566 | Brand Terms | 234567 | RESPONSIVE_SEARCH_AD | Official Site | Best Products | Shop authentic products | https://example.com |
Keywords Sheet
Campaign ID | Campaign Name | Ad Group ID | Ad Group Name | Keyword ID | Keyword Text | Match Type | Status |
---|---|---|---|---|---|---|---|
1234567890 | Summer Promotion | 11223344 | Women’s Clothing | 12345 | summer dresses | BROAD | ENABLED |
1234567890 | Summer Promotion | 11223344 | Women’s Clothing | 23456 | summer fashion sale | PHRASE | ENABLED |
Key Components Breakdown
- Main Function:
- Creates a new Google Sheets spreadsheet with five sheets (tabs)
- Calculates the date from 30 days ago
- Calls specialized functions to populate each sheet
- Logs the URL of the completed spreadsheet
- Helper Functions:
getDateString()
: Formats dates in the required Google Ads API format (YYYYMMDD)
- Data Extraction Functions: a.
fetchCampaigns()
:- Adds header row with campaign attributes
- Retrieves campaigns created in the last 30 days
- For each campaign, collects detailed information including:
- Campaign settings (ID, name, status, type)
- Budget and bidding strategy
- Date ranges
- Geographic targeting (locations included/excluded)
- Language targeting
- Returns a list of campaign IDs for use in other functions
fetchAdGroups()
:- Lists all ad groups within the retrieved campaigns
- Records campaign associations and status information
fetchAds()
:- Handles different ad formats with a flexible structure
- Captures up to 15 headlines and 4 descriptions to accommodate Responsive Search Ads
- Includes error handling for different ad types that may not have all properties
- Records final URLs
fetchKeywords()
:- Lists all keywords within the relevant campaigns
- Includes match type and status information
- Maintains relationships to campaigns and ad groups
fetchExtensions()
(not fully shown):- Would extract ad extensions like sitelinks, callouts, etc.
Why This Is Useful?
This script provides several key benefits:
- Account Documentation: Creates a complete record of recent campaign structures, which is valuable for account management and client reporting
- Audit Preparation: Having this data organized makes it easier to audit account structures and identify optimization opportunities
- Cross-Account Analysis: The standardized format allows for easy comparison across multiple accounts or time periods
- Data Backup: Provides an external backup of your campaign structures outside of Google Ads
- Troubleshooting: Makes it easier to diagnose issues by having all related components in one document with clear relationships
The script includes robust error handling to ensure that variations in ad types or missing data don’t cause the script to fail, and it maintains the hierarchical relationships between campaigns, ad groups, ads, and keywords throughout the report.
Steps to Implement Google Ads Script
To implement Google Ads scripts effectively, I’ll walk you through the process step by step:
- Access Google Ads Scripts
- Log into your Google Ads account
- Click on “Tools & Settings” in the top navigation
- Select “Scripts” under the “Bulk Actions” section
- Create a New Script
- Click the blue “+” button
- Give your script a descriptive name that reflects its purpose
- Write or Paste Your Script
- Use the built-in editor to write JavaScript code
- Google Ads scripts use a specialized JavaScript API specific to Google Ads
- Test Your Script
- Click “Preview” to test your script without making changes
- Review logs and check for errors in the execution panel
- Authorize API Access
- Grant appropriate permissions when prompted
- This allows the script to interact with your account data
- Schedule Your Script (Optional)
- Set frequency (hourly, daily, weekly, monthly)
- Choose specific times for execution
- Save and Run Your Script
- Click “Save” to store your script
- Click “Run” to execute it immediately if needed