Expert guidance for Google Ads Script development including AdsApp API, campaign management, ad groups, keywords, bidding strategies, performance reporting, budget management, automated rules, and optimization patterns. Use when automating Google Ads campaigns, managing keywords and bids, creating performance reports, implementing automated rules, optimizing ad spend, working with campaign budgets, monitoring quality scores, tracking conversions, pausing low-performing keywords, adjusting bids based on ROAS, or building Google Ads automation scripts. Covers campaign operations, keyword targeting, bid optimization, conversion tracking, error handling, and JavaScript-based automation in Google Ads editor.
/plugin marketplace add henkisdabro/wookstar-claude-code-plugins/plugin install henkisdabro-marketing-marketing@henkisdabro/wookstar-claude-code-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/bid-manager-template.jsassets/campaign-optimizer-template.jsreferences/ads-api-reference.mdscripts/validators.pyThis skill provides comprehensive guidance for developing Google Ads Scripts using the AdsApp API. Google Ads Scripts enable automation of campaign management, bid optimization, performance reporting, and bulk operations through JavaScript code that runs directly in the Google Ads editor.
Invoke this skill when:
Manage campaigns programmatically including creation, modification, status changes, and bulk updates. The AdsApp.campaigns() selector provides filtering and iteration patterns.
Common operations:
Automate keyword targeting and bid adjustments based on performance metrics.
Common operations:
Generate custom reports using campaign, ad group, keyword, and ad statistics.
Common operations:
Control spending and allocate budgets across campaigns.
Common operations:
Build intelligence into campaign management with automated decision-making.
Common operations:
Implement robust error handling to manage API limits, quota issues, and runtime errors.
Key patterns:
function pauseLowQualityKeywords() {
const keywords = AdsApp.keywords()
.withCondition('keyword.status = ENABLED')
.withCondition('keyword.quality_info.quality_score < 4')
.withCondition('keyword.metrics.cost > 100000000') // >100 spend
.get();
let count = 0;
while (keywords.hasNext()) {
const keyword = keywords.next();
keyword.pause();
count++;
}
Logger.log(`Paused ${count} low-quality keywords`);
}
function optimizeBidsByROAS() {
const TARGET_ROAS = 3.0; // 300%
const keywords = AdsApp.keywords()
.withCondition('keyword.status = ENABLED')
.withCondition('keyword.metrics.conversions > 5') // Min conversions
.get();
while (keywords.hasNext()) {
const keyword = keywords.next();
const stats = keyword.getStatsFor('LAST_30_DAYS');
const roas = stats.getReturnOnAdSpend();
const currentBid = keyword.getMaxCpc();
if (roas > TARGET_ROAS) {
// Increase bid by 10%
keyword.setMaxCpc(Math.floor(currentBid * 1.1));
} else if (roas < TARGET_ROAS * 0.7) {
// Decrease bid by 5%
keyword.setMaxCpc(Math.floor(currentBid * 0.95));
}
}
}
function exportCampaignPerformance() {
const campaigns = AdsApp.campaigns()
.withCondition('campaign.status = ENABLED')
.orderBy('campaign.metrics.cost DESC')
.get();
const report = [['Campaign', 'Clicks', 'Cost', 'Conversions', 'CPC', 'ROAS']];
while (campaigns.hasNext()) {
const campaign = campaigns.next();
const stats = campaign.getStatsFor('LAST_30_DAYS');
report.push([
campaign.getName(),
stats.getClicks(),
stats.getCost() / 1000000, // Convert from micros
stats.getConversions(),
stats.getAverageCpc() / 1000000,
stats.getReturnOnAdSpend()
]);
}
// Write to Google Sheets
const ss = SpreadsheetApp.openById('YOUR_SHEET_ID');
const sheet = ss.getSheetByName('Campaign Report') || ss.insertSheet('Campaign Report');
sheet.clear();
sheet.getRange(1, 1, report.length, report[0].length).setValues(report);
}
For comprehensive API documentation, code patterns, and detailed examples, see:
The reference file contains:
Avoid individual API calls in loops. Instead, collect entities and perform batch operations:
// ✅ Good - Batch collection
const keywords = AdsApp.keywords()
.withCondition('keyword.quality_info.quality_score < 5')
.get();
const toUpdate = [];
while (keywords.hasNext()) {
toUpdate.push(keywords.next());
}
toUpdate.forEach(keyword => keyword.setMaxCpc(50000));
Use .withCondition() to filter at the API level rather than in JavaScript:
// ✅ Good - API-level filtering
const campaigns = AdsApp.campaigns()
.withCondition('campaign.status = ENABLED')
.withCondition('campaign.budget_information.budget_amount > 100000000')
.get();
Always wrap operations in try-catch blocks and log errors:
function safeOperation() {
try {
// Operation code
} catch (error) {
Logger.log('Error: ' + error.message);
Logger.log('Stack: ' + error.stack);
// Optionally email alert
MailApp.sendEmail(
Session.getEffectiveUser().getEmail(),
'Ads Script Error',
error.message
);
}
}
Scripts have a 30-minute execution timeout. For large accounts:
.withLimit()Google Ads API uses micros (1/1,000,000) for currency values:
const costMicros = stats.getCost();
const costCurrency = costMicros / 1000000; // Convert to dollars/local currency
const bidCurrency = 5.00; // $5.00
const bidMicros = bidCurrency * 1000000; // 5000000 micros
Maintain audit trails by logging changes to Google Sheets:
function logChange(operation, entity, details) {
const ss = SpreadsheetApp.openById('LOG_SHEET_ID');
const sheet = ss.getSheetByName('Audit Log');
sheet.appendRow([
new Date(),
operation,
entity,
JSON.stringify(details)
]);
}
function adjustBidsBasedOnDayOfWeek() {
const today = new Date().getDay(); // 0 = Sunday, 6 = Saturday
const isWeekend = today === 0 || today === 6;
const campaigns = AdsApp.campaigns()
.withCondition('campaign.status = ENABLED')
.get();
while (campaigns.hasNext()) {
const campaign = campaigns.next();
const budget = campaign.getBudget().getAmount();
if (isWeekend) {
campaign.getBudget().setAmount(budget * 1.2); // +20% on weekends
}
}
}
function monitorQualityScores() {
const threshold = 5;
const lowQualityKeywords = AdsApp.keywords()
.withCondition(`keyword.quality_info.quality_score < ${threshold}`)
.withCondition('keyword.status = ENABLED')
.orderBy('keyword.metrics.cost DESC') // Most expensive first
.withLimit(100)
.get();
const alerts = [];
while (lowQualityKeywords.hasNext()) {
const keyword = lowQualityKeywords.next();
alerts.push({
keyword: keyword.getText(),
qualityScore: keyword.getQualityScore(),
cost: keyword.getStatsFor('LAST_7_DAYS').getCost() / 1000000
});
}
if (alerts.length > 0) {
// Send email or log to sheet
Logger.log(`${alerts.length} keywords with QS < ${threshold}`);
}
}
Use the validation scripts in scripts/ for pre-deployment checks:
Common Issues:
.withLimit() or process in batchesDebug with Logger:
Logger.log('Debug info: ' + JSON.stringify(data));
// View logs: View > Logs in script editor
This skill provides production-ready patterns for Google Ads automation. Consult the comprehensive API reference for detailed method signatures and advanced use cases.
Use when working with Payload CMS projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.