// Documentation: https://adssystem.store/scripts/disapproved-ads-alert/ // Writes: Nothing. Read-only. // Disapproved ads alert // Lists every enabled ad in an enabled ad group and campaign whose approval status is // not APPROVED, with the policy topics behind it. Also flags ad groups that have no // servable ad left, which is the failure that actually stops traffic. // Read-only: it reports, it pauses nothing. var EMAIL = ''; // leave empty to log only var INCLUDE_LIMITED = true; // APPROVED_LIMITED still serves, but with restrictions function main() { var rows = AdsApp.search( 'SELECT campaign.name, ad_group.id, ad_group.name, ' + ' ad_group_ad.ad.id, ad_group_ad.ad.type, ' + ' ad_group_ad.policy_summary.approval_status, ' + ' ad_group_ad.policy_summary.policy_topic_entries ' + 'FROM ad_group_ad ' + 'WHERE ad_group_ad.status = "ENABLED" ' + ' AND ad_group.status = "ENABLED" ' + ' AND campaign.status = "ENABLED"' ); var problems = []; var perGroup = {}; // ad group id -> { name, campaign, total, servable } var seen = 0; while (rows.hasNext()) { var r = rows.next(); seen += 1; var gid = String(r.adGroup.id); var status = r.adGroupAd.policySummary ? String(r.adGroupAd.policySummary.approvalStatus) : 'UNKNOWN'; if (!perGroup[gid]) { perGroup[gid] = { name: String(r.adGroup.name), campaign: String(r.campaign.name), total: 0, servable: 0 }; } perGroup[gid].total += 1; if (status === 'APPROVED' || status === 'APPROVED_LIMITED') { perGroup[gid].servable += 1; } var report = (status !== 'APPROVED') && (INCLUDE_LIMITED || status !== 'APPROVED_LIMITED'); if (report) { problems.push({ campaign: String(r.campaign.name), adGroup: String(r.adGroup.name), adId: String(r.adGroupAd.ad.id), adType: String(r.adGroupAd.ad.type), status: status, topics: policyTopics(r) }); } } Logger.log(seen + ' enabled ads checked.'); if (!seen) { Logger.log('No enabled ads found. That is itself worth checking.'); return; } var empty = []; for (var gid2 in perGroup) { if (perGroup[gid2].servable === 0) { empty.push(perGroup[gid2]); } } if (!problems.length && !empty.length) { Logger.log('Every enabled ad is approved.'); return; } var lines = []; if (empty.length) { lines.push('AD GROUPS WITH NO SERVABLE AD (' + empty.length + ')'); lines.push('campaign\tad group\tads'); for (var e = 0; e < empty.length; e++) { lines.push(empty[e].campaign + '\t' + empty[e].name + '\t' + empty[e].total); } lines.push(''); } if (problems.length) { lines.push('ADS NOT FULLY APPROVED (' + problems.length + ')'); lines.push('campaign\tad group\tad id\ttype\tstatus\tpolicy topics'); for (var p = 0; p < problems.length; p++) { var x = problems[p]; lines.push([x.campaign, x.adGroup, x.adId, x.adType, x.status, x.topics].join('\t')); } } var body = AdsApp.currentAccount().getName() + '\n' + lines.join('\n') + '\n\nAn ad group with no servable ad is not serving at all. Fix those first.'; Logger.log(body); if (EMAIL) { MailApp.sendEmail( EMAIL, 'Ad approval issues (' + (problems.length + empty.length) + ') - ' + AdsApp.currentAccount().getName(), body ); } } function policyTopics(row) { var s = row.adGroupAd.policySummary; if (!s || !s.policyTopicEntries || !s.policyTopicEntries.length) { return ''; } var names = []; for (var i = 0; i < s.policyTopicEntries.length; i++) { var entry = s.policyTopicEntries[i]; var topic = entry.topic ? String(entry.topic) : ''; var type = entry.type ? String(entry.type) : ''; names.push(type ? (topic + ' (' + type + ')') : topic); } return names.join('; '); }