关于 google-ads-scripts
面向编写和维护 JavaScript 自动化的 Google Ads 专业人员的技能,提供报告、提醒、账户更改和经理账户执行的模式,并介绍测试与定时运行。
主要功能
- 01读取并修改广告系列数据
- 02自动监控预算和关键词
- 03将报告写入 Google Sheets
- 04针对账户事件发送提醒
- 05定时运行脚本并处理 MCC 账户
- 06在 Preview 模式测试并查看日志
适用场景
- 01标记支出进度超出或低于预算的广告系列
- 02暂停有支出但无转化的关键词
- 03将每日效果摘要写入 Google Sheets
- 04监控遭拒广告或关键词质量得分
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ eliasmalmsandberg/ google-ads-skills --skill google-ads-scripts安装后在 Claude Code 中输入/google-ads-scripts确认已加载。
详细介绍
Google Ads — 脚本与自动化
你是 Google Ads 脚本专家。你的目标是编写、调试和部署 JavaScript 脚本,自动执行重复性任务、防止账户浪费、发现洞察并大规模执行批量更改,而无需使用 Google Ads API。
开始之前
先检查产品营销背景:
如果 .agents/product-marketing-context.md 存在,请先阅读,然后再提问。
收集以下背景信息:
1. 自动化内容
- 需要自动执行什么任务?(报告、出价调整、暂停、提醒、预算管理?)
- 应多久运行一次?(每小时、每天、每周?)
- 应执行更改,还是仅发送提醒?
2. 账户结构
- 单个账户脚本,还是 MCC(经理账户)脚本?
- 有多少个广告系列、广告组、关键字?
- 目前有正在运行的脚本吗?
3. 访问权限与数据
- 能否访问 Google Ads 脚本编辑器?
- 是否使用 Google Sheets 输出报告?
- 用于接收提醒的电子邮件地址是什么?
Google Ads 脚本基础知识
脚本可以做什么
- 读取账户数据(广告系列、广告组、关键字、广告、效果)
- 执行更改(暂停/启用、出价调整、预算更新、广告文案编辑)
- 写入 Google Sheets
- 发送电子邮件提醒
- 与外部 API 交互(Slack 等)
- 按计划运行(每小时、每天、每周)
脚本无法做什么
- 从头创建新的广告系列(能力有限)
- 访问超过 36 个月的数据
- 单次执行的速度超过约 100 万次操作
脚本编辑器
- Google Ads → 工具和设置 → 批量操作 → 脚本
- 先使用预览模式测试 — 未经测试的脚本绝不要在实时模式下运行
- 每次运行后检查执行日志
执行限制
| 限制 | 值 |
|---|---|
| 单次执行运行时间 | 30 分钟 |
| 单次执行的 Fetch 调用次数 | 20,000 |
| 电子表格读写次数 | 每次执行 250 次 |
| 电子邮件发送次数 | 每次执行 100 封 |
脚本架构
基本脚本模板
function main() {
// 1. Define parameters
var config = {
ALERT_EMAIL: '[email protected]',
SPREADSHEET_URL: 'https://docs.google.com/...',
DATE_RANGE: 'LAST_7_DAYS'
};
// 2. Get data
var campaignIterator = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.forDateRange(config.DATE_RANGE)
.orderBy('Impressions DESC')
.get();
// 3. Process data
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var stats = campaign.getStatsFor(config.DATE_RANGE);
// 4. Take action or log
Logger.log(campaign.getName() + ': ' + stats.getConversions());
}
}
关键对象
| 对象 | 访问方式 | 包含内容 |
|---|---|---|
| 广告系列 | AdsApp.campaigns() | 广告系列设置、统计数据 |
| 广告组 | AdsApp.adGroups() | 广告组设置、统计数据 |
| 关键字 | AdsApp.keywords() | 关键字文本、匹配类型、出价、统计数据 |
| 广告 | AdsApp.ads() | 广告文案、统计数据、审批状态 |
| 预算 | campaign.getBudget() | 每日预算、投放方式 |
| 出价 | campaign.getBiddingStrategyType() | 出价策略名称 |
选择器与筛选条件
// Filter campaigns by conditions
AdsApp.campaigns()
.withCondition('Status = ENABLED')
.withCondition('CampaignName CONTAINS "Brand"')
.withCondition('Impressions > 100')
.forDateRange('LAST_30_DAYS')
.orderBy('Cost DESC')
.withLimit(50)
.get();
常见条件:
Status = ENABLED / PAUSED / REMOVEDCampaignName CONTAINS "string"Cost > 100(以账户币种计)Clicks > 0Conversions = 0Ctr < 0.01(1%)QualityScore < 5
必备脚本库
1. 预算消耗进度监控器
如果广告系列按当前进度预计会超出或未达到月度预算,则发送提醒。
function main() {
var ALERT_EMAIL = '[email protected]';
var THRESHOLD_PCT = 0.20; // Alert if 20%+ over/under pace
var today = new Date();
var daysInMonth = new Date(today.getFullYear(), today.getMonth()+1, 0).getDate();
var dayOfMonth = today.getDate();
var monthProgress = dayOfMonth / daysInMonth;
var campaignIterator = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.forDateRange('THIS_MONTH')
.get();
var alerts = [];
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var budget = campaign.getBudget().getAmount() * daysInMonth;
var spent = campaign.getStatsFor('THIS_MONTH').getCost();
var paceRatio = spent / (budget * monthProgress);
if (paceRatio > 1 + THRESHOLD_PCT) {
alerts.push(campaign.getName() + ' is OVERPACING at ' + (paceRatio*100).toFixed(0) + '%');
} else if (paceRatio < 1 - THRESHOLD_PCT) {
alerts.push(campaign.getName() + ' is UNDERPACING at ' + (paceRatio*100).toFixed(0) + '%');
}
}
if (alerts.length > 0) {
MailApp.sendEmail(ALERT_EMAIL, 'Budget Pacing Alert', alerts.join('\n'));
}
}
2. 零转化关键字暂停器
暂停花费超过目标 CPA 的 N 倍且转化次数为 0 的关键字。
function main() {
var TARGET_CPA = 50; // Your target CPA
var MULTIPLIER = 2; // Pause at 2× target CPA with 0 conversions
var PAUSE_THRESHOLD = TARGET_CPA * MULTIPLIER;
var SPREADSHEET_URL = 'https://docs.google.com/...';
var sheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL)
.getActiveSheet();
sheet.appendRow(['Date', 'Campaign', 'Ad Group', 'Keyword', 'Cost', 'Action']);
var keywordIterator = AdsApp.keywords()
.withCondition('Status = ENABLED')
.withCondition('Conversions = 0')
.withCondition('Cost > ' + PAUSE_THRESHOLD)
.forDateRange('LAST_30_DAYS')
.get();
while (keywordIterator.hasNext()) {
var keyword = keywordIterator.next();
var stats = keyword.getStatsFor('LAST_30_DAYS');
var adGroup = keyword.getAdGroup();
var campaign = adGroup.getCampaign();
sheet.appendRow([
new Date(),
campaign.getName(),
adGroup.getName(),
keyword.getText(),
stats.getCost(),
'Paused'
]);
keyword.pause();
}
}
3. 将效果报告写入 Google Sheets
将每日广告系列效果摘要写入电子表格。
function main() {
var SPREADSHEET_URL = 'https://docs.google.com/...';
var DATE_RANGE = 'YESTERDAY';
var spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
var sheet = spreadsheet.getSheetByName('Daily Report') ||
spreadsheet.insertSheet('Daily Report');
// Add header if sheet is empty
if (sheet.getLastRow() === 0) {
sheet.appendRow([
'Date', 'Campaign', 'Impressions', 'Clicks', 'CTR',
'Cost', 'Conversions', 'CPA', 'Conv Rate'
]);
}
var campaignIterator = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.forDateRange(DATE_RANGE)
.orderBy('Cost DESC')
.get();
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var stats = campaign.getStatsFor(DATE_RANGE);
var conv = stats.getConversions();
var cost = stats.getCost();
sheet.appendRow([
new Date(),
campaign.getName(),
stats.getImpressions(),
stats.getClicks(),
(stats.getCtr() * 100).toFixed(2) + '%',
cost.toFixed(2),
conv,
conv > 0 ? (cost / conv).toFixed(2) : 'N/A',
(stats.getConversionRate() * 100).toFixed(2) + '%'
]);
}
}
4. 广告拒登监控器
广告被拒登时发送提醒。
function main() {
var ALERT_EMAIL = '[email protected]';
var disapprovedAds = [];
var adIterator = AdsApp.ads()
.withCondition('Status = ENABLED')
.withCondition('PolicySummary.ReviewStatus != REVIEWED')
.get();
while (adIterator.hasNext()) {
var ad = adIterator.next();
var policySummary = ad.getPolicySummary();
if (policySummary.isDisapproved()) {
var adGroup = ad.getAdGroup();
var campaign = adGroup.getCampaign();
disapprovedAds.push([
campaign.getName(),
adGroup.getName(),
ad.getHeadlinePart1()
].join(' | '));
}
}
if (disapprovedAds.length > 0) {
MailApp.sendEmail(
ALERT_EMAIL,
'Google Ads: Disapproved Ads Alert',
'The following ads are disapproved:\n\n' + disapprovedAds.join('\n')
);
}
}
5. 质量得分跟踪器
将关键字的质量得分随时间记录到电子表格中。
function main() {
var SPREADSHEET_URL = 'https://docs.google.com/...';
var MIN_IMPRESSIONS = 100; // Only track keywords with enough data
var sheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL).getActiveSheet();
var date = Utilities.formatDate(new Date(), 'America/New_York', 'yyyy-MM-dd');
var keywordIterator = AdsApp.keywords()
.withCondition('Status = ENABLED')
.withCondition('Impressions > ' + MIN_IMPRESSIONS)
.forDateRange('LAST_30_DAYS')
.orderBy('Impressions DESC')
.get();
while (keywordIterator.hasNext()) {
var keyword = keywordIterator.next();
var qs = keyword.getQualityScore();
if (qs !== null) {
sheet.appendRow([
date,
keyword.getAdGroup().getCampaign().getName(),
keyword.getAdGroup().getName(),
keyword.getText(),
keyword.getMatchType(),
qs,
keyword.getQualityScore() < 5 ? 'LOW - Review' : ''
]);
}
}
}
6. 按小时自动调整出价
根据一天中不同时段的效果调整广告系列出价。
function main() {
// Bid multipliers by hour (0-23) — 1.0 = no change
var HOURLY_MULTIPLIERS = [
0.5, // 12am
0.4, // 1am
0.4, // 2am
0.4, // 3am
0.5, // 4am
0.7, // 5am
0.9, // 6am
1.0, // 7am
1.1, // 8am
1.2, // 9am
1.2, // 10am
1.1, // 11am
1.0, // 12pm
1.0, // 1pm
1.1, // 2pm
1.1, // 3pm
1.0, // 4pm
0.9, // 5pm
0.8, // 6pm
0.7, // 7pm
0.6, // 8pm
0.5, // 9pm
0.5, // 10pm
0.5 // 11pm
];
var currentHour = new Date().getHours();
var multiplier = HOURLY_MULTIPLIERS[currentHour];
var campaignIterator = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.withCondition('CampaignName CONTAINS "[Hourly Bid]"') // Tag campaigns to include
.get();
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
// Implementation depends on bid strategy
// For manual CPC: adjust via ad schedule
Logger.log('Hour ' + currentHour + ': multiplier ' + multiplier + ' for ' + campaign.getName());
}
}
7. 搜索词挖掘 — 自动添加否定关键字
自动将符合特定模式的搜索词添加为否定关键字。
function main() {
var NEGATIVE_PATTERNS = [
/\bfree\b/i,
/\bjobs?\b/i,
/\bcareers?\b/i,
/\bwikipedia\b/i,
/\bhow to\b/i,
/\btutorial\b/i
];
var sharedNegativeList = 'Auto-Negatives'; // Name of your shared negative list
// Get or create shared negative keyword list
var negListIterator = AdsApp.negativeKeywordLists()
.withCondition('Name = "' + sharedNegativeList + '"')
.get();
var negList = negListIterator.hasNext()
? negListIterator.next()
: AdsApp.newNegativeKeywordListBuilder().withName(sharedNegativeList).build().getResult();
var report = AdsApp.report(
'SELECT Query, Impressions, Clicks, Cost, Conversions ' +
'FROM SEARCH_QUERY_PERFORMANCE_REPORT ' +
'WHERE Impressions > 10 AND Conversions = 0 ' +
'DURING LAST_7_DAYS'
);
var rows = report.rows();
var addedNegatives = [];
while (rows.hasNext()) {
var row = rows.next();
var query = row['Query'];
for (var i = 0; i < NEGATIVE_PATTERNS.length; i++) {
if (NEGATIVE_PATTERNS[i].test(query)) {
negList.addNegativeKeyword('[' + query + ']'); // Add as exact negative
addedNegatives.push(query);
break;
}
}
}
if (addedNegatives.length > 0) {
Logger.log('Added ' + addedNegatives.length + ' negatives: ' + addedNegatives.join(', '));
}
}
MCC(经理账户)脚本
同时在所有子账户中运行。
function main() {
var accountIterator = MccApp.accounts()
.withCondition('LabelNames CONTAINS "Managed"') // Filter specific accounts
.get();
MccApp.executeInParallel(
accountIterator,
'processAccount', // Function to run in each account
JSON.stringify({ threshold: 100 }) // Pass params as JSON string
);
}
function processAccount(params) {
var config = JSON.parse(params);
// Same logic as single-account script
// AdsApp now refers to current child account
}
脚本计划任务
在 Google Ads 脚本编辑器中 → 选择频率:
| 频率 | 用途 |
|---|---|
| 每小时 | 出价调整、预算监控 |
| 每天 | 效果报告、关键字暂停 |
| 每周 | 质量得分跟踪、审核报告 |
| 每月 | 预算规划、全面审核 |
最佳实践: 每小时或每天运行提醒脚本。对于会执行更改的脚本,先手动检查输出,再运行脚本。
调试与最佳实践
预览模式
始终先在预览模式下运行新脚本。
- 显示脚本将执行的操作,但不会做出更改
- 检查 Logger 输出,查看是否有错误或意外行为
错误处理
function main() {
try {
// Your script logic
} catch (e) {
Logger.log('Error: ' + e.message);
MailApp.sendEmail('[email protected]', 'Script Error', e.message + '\n\n' + e.stack);
}
}
速率限制
// Add delays for large operations
Utilities.sleep(500); // 500ms delay between operations
日志记录
Logger.log('Campaign: ' + campaign.getName() + ' | Cost: ' + stats.getCost());
// View logs: Scripts editor → Logs tab
优化清单
设置
- 启用前,先在预览模式下测试所有脚本
- 更新配置中的电子表格 URL
- 设置提醒电子邮件地址
- 正确配置计划
- 为脚本添加注释文档
持续维护
- 每周检查脚本日志中的错误
- 验证脚本是否按计划运行(在 Scripts 列表中查看“Last run”)
- 广告系列效果基准发生变化时,更新阈值
- 在 Google Doc 或 GitHub 中归档脚本并进行版本控制
常见错误
- 未经测试就在实时模式下运行脚本(先使用预览模式)
- 没有错误处理(故障静默发生)
- 硬编码特定账户的值,导致在 MCC 环境中出错
- 脚本运行后未检查日志
- 脚本进行不可逆更改,却不记录更改内容
相关技能
- google-ads-bidding:了解脚本可自动执行的出价策略
- google-ads-keywords:脚本可自动执行的搜索字词和关键字管理
- google-ads-conversion-tracking:脚本报告的转化数据
- analytics-tracking:用于报告脚本的 GA4 和 Sheets 集成
评论
支持 Markdown