Wiki Google Ads

Báo cáo từ khóa tìm kiếm ra Spreadsheets

// Report on how close variants relate to your keywords in Google Ads
// Free AdWords Script courtesy of Optmyzr.com
// September 12, 2018
function main() {
// -----------------
// Edit this section with your preferences
// ----------------
var time = 'LAST_7_DAYS';
//Choose one from TODAY, YESTERDAY, LAST_7_DAYS, THIS_WEEK_SUN_TODAY, THIS_WEEK_MON_TODAY, LAST_WEEK, LAST_14_DAYS, LAST_30_DAYS, LAST_BUSINESS_WEEK, LAST_WEEK_SUN_SAT, THIS_MONTH
var reportVersion = 'V201809';
var emailAddresses = '';
var accountManagers = 'quansipnamnet@gmail.com';
var spreadsheetUrl = 'https://docs.google.com/spreadsheets/d/1O4Pn3nvbssOVVVDcZjPMX-gK1ADHpBv2S2CPoOENXGc/edit#gid=0';
var includeLevinsthein = 1; // set value to 0 if your script times out. by not adding this score, the script will run faster
// use 1 or none of the following two settings to limit the campaigns analyzed
var campaignNameContains = ""; // this is NOT case sensitive
var campaignNameDoesNotInclude = ""; // this is NOT case sensitive
// -------------------
// Don't make edits after this unless you know how to write scripts
// -------------------
var map = new Array();
// Get Campaign IDs
var campaignsToCheck = new Array();
if(campaignNameDoesNotInclude) {
if(campaignNameDoesNotInclude.indexOf("'") != -1)
{
var doesNotContainString = '"' + campaignNameDoesNotInclude + '"';
} else {
var doesNotContainString = "'" + campaignNameDoesNotInclude + "'";
}
var campaigns = AdWordsApp.campaigns()
.withCondition('Name DOES_NOT_CONTAIN_IGNORE_CASE ' + doesNotContainString)
.withCondition('Status != REMOVED')
.get();
} else if(campaignNameContains) {
if(campaignNameContains.indexOf("'") != -1)    {
var containsString = '"' + campaignNameContains + '"';
} else {
var containsString = "'" + campaignNameContains + "'";
}
var campaigns = AdWordsApp.campaigns()
.withCondition('Name CONTAINS_IGNORE_CASE ' + containsString)
.withCondition('Status != REMOVED')
.get();
} else {
var campaigns = AdWordsApp.campaigns()
.withCondition('Status != REMOVED')
.get();
}
while(campaigns.hasNext()) {
var campaign = campaigns.next();
var campaignId = campaign.getId();
Logger.log(campaignId);
campaignsToCheck.push(campaignId);
}
// Keywords
var query =
'SELECT Id, KeywordMatchType, Criteria, Clicks, Impressions, Cost, ConversionValue, Conversions, AveragePosition, Ctr, AverageCpc, AdGroupName, CampaignName, CampaignId, AdGroupId ' +
'FROM KEYWORDS_PERFORMANCE_REPORT ' +
'WHERE Impressions > 0 ' +
'AND CampaignId IN ' + JSON.stringify(campaignsToCheck) + " " +
'DURING ' + time;
var report = AdWordsApp.report(query,{apiVersion: reportVersion});
var rows = report.rows();
while(rows.hasNext()) {
var row = rows.next();
var adGroupId = row['AdGroupId'];
var id = row['Id'];
var criteria = row['Criteria'];
//Logger.log(row['Criteria']);
if(criteria.indexOf('+') != -1) {
var subMatchType = "BMM";
} else {
var subMatchType = row['KeywordMatchType'];
}
var key = adGroupId + "-" + id;
if(!map[key]) {
map[key] = new Object();
map[key].keyword = new Object();
map[key].searchTerms = new Array();
map[key].keyword.criteria = row['Criteria'];
map[key].keyword.clicks = parseInt(row['Clicks'],10);
map[key].keyword.impressions = parseInt(row['Impressions'],10);
map[key].keyword.cost = getFloat(row['Cost']);
map[key].keyword.conversions = getFloat(row['Conversions']);
map[key].keyword.ctr = getFloat(row['Ctr']);
map[key].keyword.averagePosition = getFloat(row['AveragePosition']);
map[key].keyword.averageCpc = getFloat(row['AverageCpc']);
map[key].keyword.conversionValue = getFloat(row['ConversionValue']);
map[key].keyword.matchType = row['KeywordMatchType'];
map[key].keyword.subMatchType = subMatchType;
map[key].keyword.campaignName = row['CampaignName'];
map[key].keyword.adGroupName = row['AdGroupName'];
}
}
Logger.log("");
// Search Terms
var query =
'SELECT KeywordId, KeywordTextMatchingQuery, Query, QueryMatchTypeWithVariant, Clicks, Impressions, Cost, ConversionValue, Conversions, AveragePosition, Ctr, AverageCpc, AdGroupName, CampaignName, CampaignId, AdGroupId ' +
'FROM SEARCH_QUERY_PERFORMANCE_REPORT ' +
'WHERE Impressions > 0 ' +
'AND CampaignId IN ' + JSON.stringify(campaignsToCheck) + " " +
'DURING ' + time;
var report = AdWordsApp.report(query,{apiVersion: reportVersion});
var rows = report.rows();
while(rows.hasNext()) {
var row = rows.next();
var adGroupId = row['AdGroupId'];
var id = row['KeywordId'];
var query = row['Query'];
//Logger.log(query);
var key = adGroupId + "-" + id;
if(!map[key]) {
// most likely a shopping campaign
// Logger.log("query not associated with kw in campaign: " + row['CampaignName']);
} else {
if(!map[key].searchTerms[query]) {
map[key].searchTerms[query] = new Object();
map[key].searchTerms[query].matchTypeVariant = row['QueryMatchTypeWithVariant'];
map[key].searchTerms[query].clicks = parseInt(row['Clicks'],10); 
map[key].searchTerms[query].impressions = parseInt(row['Impressions'],10);
map[key].searchTerms[query].cost = getFloat(row['Cost']);
map[key].searchTerms[query].conversions = getFloat(row['Conversions']);
map[key].searchTerms[query].ctr = getFloat(row['Ctr']);
map[key].searchTerms[query].averagePosition = getFloat(row['AveragePosition']);
map[key].searchTerms[query].averageCpc = getFloat(row['AverageCpc']);
map[key].searchTerms[query].conversionValue = getFloat(row['ConversionValue']);
map[key].searchTerms[query].impressions = parseInt(row['Impressions'],10);
map[key].searchTerms[query].campaignName = row['CampaignName']; 
}
}
}
// Spreadsheet
var reportDate = new Date();
var dateForFilename = reportDate.yyyymmdd();
if(spreadsheetUrl.toLowerCase().indexOf("new") != -1)
{
var spreadsheet = SpreadsheetApp.create("Keyword Analysis - " + AdWordsApp.currentAccount().getName() + " - " + dateForFilename + " (" + time + ")");
var spreadsheetUrl = spreadsheet.getUrl();
} 
var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetUrl);
if(accountManagers && accountManagers!=""){
var accountManagersArray = accountManagers.replace(/\s/g, "").split(",");
spreadsheet.addEditors(accountManagersArray);
}
// Sheet for Keyword Report
//get all sheets except first and delete them and insert new sheets every time to avoid name error
var allSheets = spreadsheet.getSheets();
for(var i=1,len=allSheets.length;i<len;i++){ spreadsheet.deleteSheet(allSheets[i]); } allSheets[0].setName("Keywords"); var kwSheet = allSheets[0]; kwSheet.appendRow(["Campaign Name", "Ad Group Name", "Match Type", "Sub Match Type", "Keyword", "Search Term", "Query Match Type with Variant", "Levenshtein distance", "KW Clicks", "KW Impressions", "KW Cost", "KW CTR", "KW Avg. CPC", "KW Conversions", "KW Conv. Value", "KW Avg Pos.", "Query Clicks", "Query Impressions", "Query Cost", "Query CTR", "Query Avg. CPC", "Query Conversions", "Query Conv. Value", "Query Avg Pos."]); kwSheet.setFrozenRows(1); // Render for(var key in map) { //Logger.log(key); var criteria = map[key].keyword.criteria; var matchType = map[key].keyword.matchType; var subMatchType = map[key].keyword.subMatchType; var kwClicks = map[key].keyword.clicks; var kwImpressions = map[key].keyword.impressions; var kwConversions = map[key].keyword.conversions; var kwCost = map[key].keyword.cost; var kwCtr = map[key].keyword.ctr; var kwAverageCpc = map[key].keyword.averageCpc; var kwConversionValue = map[key].keyword.conversionValue; var kwAveragePosition = map[key].keyword.averagePosition; var campaignName = map[key].keyword.campaignName; var adGroupName = map[key].keyword.adGroupName; for(var query in map[key].searchTerms) { var queryClicks = map[key].searchTerms[query].clicks; var matchTypeVariant = map[key].searchTerms[query].matchTypeVariant; //Logger.log(criteria + " | " + query + " | " + matchType + " " + matchTypeVariant); if(matchType.toLowerCase() != matchTypeVariant.toLowerCase()) { //var difference = getDifference(criteria, query); //var diffLen = difference.length; var rawCriteria = criteria.replace(/\+/g,""); if(includeLevinsthein) { var diffLen = levDist(rawCriteria, query); } else { var diffLen = ""; } var queryClicks = map[key].searchTerms[query].clicks; var queryImpressions = map[key].searchTerms[query].impressions; var queryConversions = map[key].searchTerms[query].conversions; var queryCost = map[key].searchTerms[query].cost; var queryCtr = map[key].searchTerms[query].ctr; var queryAverageCpc = map[key].searchTerms[query].averageCpc; var queryConversionValue = map[key].searchTerms[query].conversionValue; var queryAveragePosition = map[key].searchTerms[query].averagePosition; //Logger.log(criteria + " " + matchType + " " + query + " " + matchTypeVariant + " " + kwClicks + " " + " " + diffLen); kwSheet.appendRow([campaignName, adGroupName, matchType, subMatchType, "'"+criteria, query, matchTypeVariant, diffLen, kwClicks, kwImpressions, kwCost, kwCtr, kwAverageCpc, kwConversions, kwConversionValue, kwAveragePosition, queryClicks, queryImpressions, queryCost, queryCtr, queryAverageCpc, queryConversions, queryConversionValue, queryAveragePosition]); } } } // Notify Logger.log(spreadsheetUrl); var body = "your report is ready at: " + spreadsheetUrl; MailApp.sendEmail(emailAddresses, "notifications@optmyzr.com", "Your match type analysis is ready", body); } // date functions Date.prototype.yyyymmdd = function() { var yyyy = this.getFullYear().toString(); var mm = (this.getMonth()+1).toString(); // getMonth() is zero-based var dd = this.getDate().toString(); return yyyy + (mm[1]?mm:"0"+mm[0]) + (dd[1]?dd:"0"+dd[0]); // padding }; function getFloat (input) { if(!input || input == "" || typeof(input) === 'undefined') var input = "0.0"; input = input.toString(); var output = parseFloat(input.replace(/,/g, "")); return output; } // Function: levDist // Author James Westgate (https://stackoverflow.com/users/305319/james-westgate) // Source: https://stackoverflow.com/questions/11919065/sort-an-array-by-the-levenshtein-distance-with-best-performance-in-javascript/11958496#11958496 // License: CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/) function levDist(s, t) { var d = []; //2d matrix // Step 1 var n = s.length; var m = t.length; if (n == 0) return m; if (m == 0) return n; //Create an array of arrays in javascript (a descending loop is quicker) for (var i = n; i >= 0; i--) d[i] = [];
// Step 2
for (var i = n; i >= 0; i--) d[i][0] = i;
for (var j = m; j >= 0; j--) d[0][j] = j;
// Step 3
for (var i = 1; i <= n; i++) {
var s_i = s.charAt(i - 1);
// Step 4
for (var j = 1; j <= m; j++) { //Check the jagged ld total so far if (i == j && d[i][j] > 4) return n;
var t_j = t.charAt(j - 1);
var cost = (s_i == t_j) ? 0 : 1; // Step 5
//Calculate the minimum
var mi = d[i - 1][j] + 1;
var b = d[i][j - 1] + 1;
var c = d[i - 1][j - 1] + cost;
if (b < mi) mi = b;
if (c < mi) mi = c; d[i][j] = mi; // Step 6 //Damerau transposition if (i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j) {
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
}
}
}
// Step 7
return d[n][m];
}

Pause AdGroups With No Active Keywords

/*********************************************
* Pause AdGroups With No Active Keywords
* Version 1.1
* Changelog v1.1
*   - Updated for speed and added comments 
* Created By: Russ Savage
* FreeAdWordsScripts.com
**********************************************/
function main() {
// Let's start by getting all of the active AdGroups
var agIter = AdWordsApp.adGroups()
.withCondition('CampaignStatus = ENABLED')
.withCondition('Status = ENABLED')
.get();
// It is faster to store them and process them all at once later
var toPause = [];
// Then we will go through each one
while(agIter.hasNext()) {
var ag = agIter.next();
//get all the keywords that are enabled
var kwIter = ag.keywords()
.withCondition("Status = ENABLED")
.get();
//If .hasNext() is true, there is at least 1 kw in the AdGroup
var hasKw = kwIter.hasNext(); 
if(!hasKw) {
toPause.push(ag);
}
}
// Now we process them all at once to take advantage of batch processing
for(var i in toPause) {
toPause[i].pause();
}
}

Pause Duplicate Broad Keywords

/**
*
* Broad-match keyword aggregator script
* This script will group equivalent broad match keywords and label based on performence
*
* Version: 1.1
* Updated 2016-10-11: replaced 'ConvertedClicks' with 'Conversions'
* Google AdWords Script maintained by brainlabsdigital.com
*
**/
function main(){
var ACCOUNT_WIDE = false;
//Defines whether the script looks at campaign-level or account-level broad match duplicate keywords
var METRIC = "AverageCpc";
//Select the metric which will determine which duplicate keyword will be kept, choose from "Ctr", "QualityScore", "Impressions", "Conversions", "AverageCpc"
var CAMPAIGN_INCLUDE_FILTER = []; // e.g var CAMPAIGN_INCLUDE_FILTER = ["hey", "jude"];
//Campaign filter which will include any campaign with any of the included strings in the campaign name. Case insensitive matching
var CAMPAIGN_EXCLUDE_FILTER = []; // e.g var CAMPAIGN_EXCLUDE_FILTER = ["hey", "jude"];
//Campaign filter which will exclude any campaign with any of the included strings in the campaign name. Case insensitive matching
var DATE_RANGE = "LAST_30_DAYS";
//Choose one from TODAY, YESTERDAY, LAST_7_DAYS, THIS_WEEK_SUN_TODAY, THIS_WEEK_MON_TODAY, LAST_WEEK, LAST_14_DAYS, LAST_30_DAYS, LAST_BUSINESS_WEEK, LAST_WEEK_SUN_SAT, THIS_MONTH
var KEEP_LABEL = "DuplicateBroadKeyword_Enable";
//Label one keyword from each duplicate group 
var PAUSE_LABEL = "DuplicateBroadKeyword_Pause";
//Label all keywords which don't have the best statistic from selected
labelDuplicates(ACCOUNT_WIDE, CAMPAIGN_INCLUDE_FILTER, CAMPAIGN_EXCLUDE_FILTER, DATE_RANGE, METRIC, KEEP_LABEL, PAUSE_LABEL);
}
function labelDuplicates(ACCOUNT_WIDE, CAMPAIGN_INCLUDE_FILTER, CAMPAIGN_EXCLUDE_FILTER, DATE_RANGE, METRIC, KEEP_LABEL, PAUSE_LABEL) {
//Create labels
AdWordsApp.createLabel(KEEP_LABEL);
AdWordsApp.createLabel(PAUSE_LABEL);
//Metric data-validation
var allowedMetrics = ["Ctr", "QualityScore", "Impressions", "Conversions", "AverageCpc"];
var allowedMetrics_lowerCase = allowedMetrics.map(function (str){return str.toLowerCase()});
var metricIndex = allowedMetrics_lowerCase.indexOf(METRIC.toLowerCase());
if(metricIndex === -1){
var error = "Metric '" + METRIC + "' not recognised, please set to one from '" + allowedMetrics.join("', '") + "'.";
Logger.log(error);
throw error;
return;
}
var METRIC = allowedMetrics[metricIndex];
//Generate list of included campaigns
var includeCampaignIds = [];
var campaignIncludes = CAMPAIGN_INCLUDE_FILTER.map(function (str){return str.toLowerCase()});
var campaignIterator = AdWordsApp.campaigns()
.withCondition("CampaignStatus = ENABLED")
.get();
while(campaignIterator.hasNext()){
var campaign = campaignIterator.next();
var campaignId = campaign.getId();
var campaignName = campaign.getName();
var campaignNameLower = campaignName.toLowerCase();
var flag = false;
for(var i = 0; i < campaignIncludes.length; i++){ if(campaignNameLower.indexOf(campaignIncludes[i]) !== -1){ flag = true; break; } } if(flag){ includeCampaignIds.push(campaignId); } } //Construct AWQL report query var selectQuery = 'SELECT CampaignName, CampaignId, Id, AdGroupId, Criteria, ' + METRIC + ' '; var fromQuery = 'FROM KEYWORDS_PERFORMANCE_REPORT '; var whereQuery = "WHERE KeywordMatchType = BROAD AND AdNetworkType1 = SEARCH "; if(includeCampaignIds.length > 0){
whereQuery += "AND CampaignId IN [" + includeCampaignIds.join(",") + "] ";
}
for(var i = 0; i < CAMPAIGN_EXCLUDE_FILTER.length; i++){ whereQuery += "AND CampaignName DOES_NOT_CONTAIN_IGNORE_CASE '" + CAMPAIGN_EXCLUDE_FILTER[i] + "' "; } var duringQuery = "DURING " + DATE_RANGE; var query = selectQuery + fromQuery + whereQuery + duringQuery; //Generate report var report = AdWordsApp.report(query); //Poll report rows var campaignKeywords = {}; var rows = report.rows(); while(rows.hasNext()){ var row = rows.next(); var keywordId = row['Id']; var adGroupId = row['AdGroupId']; var campaignId = row['CampaignId']; var keywordText = row['Criteria'].toLowerCase(); var metricStat = parseFloat(row[METRIC].replace(/,/g, "")); if(METRIC.toLowerCase() === "AverageCpc".toLowerCase()){ if(metricStat > 0){
metricStat = 1 / metricStat;
}
}
var stats = {metric: metricStat};
if(ACCOUNT_WIDE) campaignId = 1;
if(typeof(campaignKeywords[campaignId]) === "undefined"){
campaignKeywords[campaignId] = [];
}
campaignKeywords[campaignId].push(parseKeyword(keywordId,adGroupId,keywordText,stats));
}
//Establish duplicate keyword groups
if (ACCOUNT_WIDE === true){
var keywordGroups = {};
}
for(var campaignId in campaignKeywords){
if (ACCOUNT_WIDE === false) {
var keywordGroups = {};
}
var campaignKeywordsList = campaignKeywords[campaignId];
var keywordArray = [];
for(var keyword in campaignKeywordsList){
keywordArray.push(campaignKeywordsList[keyword]["Text"]);
}
for(var keyword in campaignKeywordsList){
var keywordText = campaignKeywordsList[keyword]["Text"];
var firstIndex = keywordArray.indexOf(keywordText);
var lastIndex = keywordArray.lastIndexOf(keywordText);
//push the dupes into dupe groups
if(firstIndex !== lastIndex){
if(typeof(keywordGroups[keywordText]) === "undefined") {
keywordGroups[keywordText]=[];
}
keywordGroups[keywordText].push(campaignKeywordsList[keyword]);
}
}
if (ACCOUNT_WIDE === true) {
continue;
}
labelKeywords(keywordGroups, KEEP_LABEL, PAUSE_LABEL);
}
if (ACCOUNT_WIDE === true) {
labelKeywords(keywordGroups, KEEP_LABEL, PAUSE_LABEL);
}
}
function parseKeyword(keywordId,adGroupId,keywordText, stats){
var keyword = {};
keyword["KeywordId"] = keywordId;
keyword["AdGroupId"] = adGroupId;
keyword["Id"] = [adGroupId, keywordId];
keyword["Text"] = orderKeyword(keywordText);
keyword["Stats"] = stats;
return keyword;
}
function orderKeyword(keywordText){
//Splitting the words
var keywordTextArray = keywordText.trim().split(" ");
//Sort keyword components
var sortedKeywordComponents = keywordTextArray.sort();
//Turn sorted strings into one word
var sortedKeyword = sortedKeywordComponents.join(" ");
return sortedKeyword; 
}
function labelKeywords(keywordGroups, KEEP_LABEL, PAUSE_LABEL) {
for (var keywordText in keywordGroups) {
//cycle through each group to pick best of the bunch
var maxMetric = -1;
var bestKeyword = [];
for (var keyword in keywordGroups[keywordText]) {
if (parseFloat(keywordGroups[keywordText][keyword]["Stats"]["metric"]) > maxMetric) {
maxMetric = keywordGroups[keywordText][keyword]["Stats"]["metric"];
bestKeyword[0] = keywordGroups[keywordText][keyword];
}
}
var indexOfBest = keywordGroups[keywordText].indexOf(bestKeyword[0]);
keywordGroups[keywordText].splice(indexOfBest, 1);
//label all groups with pause/unpause labels
var keywordIterator = AdWordsApp.keywords().withIds([bestKeyword[0]["Id"]]).get();
keywordIterator.next().applyLabel(KEEP_LABEL);
var keywordIdArray = [];
for (keyword in keywordGroups[keywordText]) {
keywordIdArray.push(keywordGroups[keywordText][keyword]["Id"]);
} 
var keywordIterator = AdWordsApp.keywords().withIds(keywordIdArray).get();
while (keywordIterator.hasNext()){
var keyword = keywordIterator.next();
keyword.applyLabel(PAUSE_LABEL);
}
}
}

Giới hạn ngân sách

function main() {
var allowedOverdeliveryPercentage = 0.2; // set percentage as decimal, i.e. 20% should be set as 0.2
var labelName = "paused by overdelivery checker script";
AdWordsApp.createLabel(labelName, "automatic label needed to reenable campaigns");
var campaigns = AdWordsApp.campaigns()
.withCondition("Status = ENABLED")
.withCondition("Cost > 0")
.forDateRange("TODAY");
var campaignIterator = campaigns.get();
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var campaignName = campaign.getName();
var budgetAmount = campaign.getBudget().getAmount();
var costToday = campaign.getStatsFor("TODAY").getCost();
if(costToday > budgetAmount * (1 + allowedOverdeliveryPercentage)) {
Logger.log(campaignName + " has spent " + costToday + " which is more than allowed.");
campaign.applyLabel(labelName);
campaign.pause();
} else {
Logger.log(campaignName + " has spent " + costToday + " and can continue to run.");
}
}
}

Figuring Out When Your Ad, AdGroup, Keyword, or Campaign Was Created| Tạo ngày tạo

Tạo xong>vào báo cáo sửa cột>thuộc tính>nhãn

/**************************************
* Track Entity Creation Date
* Version 1.4
* Changelog v1.4
* - Removed apiVersion from reporting call
* Changelog v1.3
* - Updated script to handle all entities
* Changelog v1.2
* - Fixed an issue with comparing dates
* ChangeLog v1.1
* - Updated logic to work with larger accounts
* Created By: Russ Savage
* http://www.FreeAdWordsScripts.com
**************************************/
//All my labels will start with this. For example: Created:2013-05-01
var LABEL_PREFIX = 'Created:';
var DAYS_IN_REPORT = 30;
var ENTITY = 'ad'; //or adgroup or keyword or campaign
function main() {
//First we get the impression history of our entity
var ret_map = getImpressionHistory();
//Then we apply our labels
applyLabels(ret_map);
}
//Function to apply labels to the ads in an account
function applyLabels(ret_map) {
var iter;
if(ENTITY === 'campaign') { iter = AdWordsApp.campaigns().get(); }
if(ENTITY === 'adgroup') { iter = AdWordsApp.adGroups().get(); }
if(ENTITY === 'ad') { iter = AdWordsApp.ads().get(); }
if(ENTITY === 'keyword') { iter = AdWordsApp.keywords().get(); }
while(iter.hasNext()) {
var entity = iter.next();
var id = entity.getId();
if(ret_map[id]) {
var label_name = LABEL_PREFIX+Utilities.formatDate(ret_map[id], AdWordsApp.currentAccount().getTimeZone(), "yyyy-MM-dd");
createLabelIfNeeded(label_name);
entity.applyLabel(label_name);
}
}
}
//This is a helper function to create the label if it does not already exist
function createLabelIfNeeded(name) {
if(!AdWordsApp.labels().withCondition("Name = '"+name+"'").get().hasNext()) {
AdWordsApp.createLabel(name);
}
}
//A helper function to find the date days ago
function getDateDaysAgo(days) {
var the_past = new Date();
the_past.setDate(the_past.getDate() - days);
return Utilities.formatDate(the_past,AdWordsApp.currentAccount().getTimeZone(),"yyyyMMdd");
}
//A helper function to compare dates.
//Copied from: http://goo.gl/uW48a
function diffDays(firstDate,secondDate) {
var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
return Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
}
function getImpressionHistory() {
var API_VERSION = { includeZeroImpressions : false };
var first_date = new Date('10/23/2000');
var max_days_ago = diffDays(first_date,new Date());
var cols = ['Date','Id','Impressions'];
var report = {
'campaign' : 'CAMPAIGN_PERFORMANCE_REPORT',
'adgroup' : 'ADGROUP_PERFORMANCE_REPORT',
'ad' : 'AD_PERFORMANCE_REPORT',
'keyword' : 'KEYWORDS_PERFORMANCE_REPORT'}[ENTITY];
var ret_map = {};
var prev_days_ago = 0;
for(var i = DAYS_IN_REPORT; i < max_days_ago; i+=DAYS_IN_REPORT) {
var start_date = getDateDaysAgo(i);
var end_date = getDateDaysAgo(prev_days_ago);
var date_range = start_date+','+end_date;
Logger.log('Getting data for ' + date_range);
var query = ['select',cols.join(','),'from',report,'during',date_range].join(' ');
var report_iter = AdWordsApp.report(query, API_VERSION).rows();
if(!report_iter.hasNext()) { Logger.log('No more impressions found. Breaking.'); break; } // no more entries
while(report_iter.hasNext()) {
var row = report_iter.next();
if(ret_map[row['Id']]) {
var [year,month,day] = (row['Date']).split('-');
var from_row = new Date(year, parseFloat(month)-1, day);
var from_map = ret_map[row['Id']];
if(from_row < from_map) {
ret_map[row['Id']] = from_row;
}
} else {
var [year,month,day] = (row['Date']).split('-');
ret_map[row['Id']] = new Date(year, parseFloat(month)-1, day);
}
}
prev_days_ago = i;
}
return ret_map;
}

Report on Broken Urls In Your Account

/****************************
* Find Broken Urls In Your Account
* Version 1.1
* ChangeLog v1.1
*  - Updated to only see Text Ads
* Created By: Russ Savage
* FreeAdWordsScripts.com
****************************/
function main() {
// You can add more if you want: http://goo.gl/VhIX
var BAD_CODES = [400,404,500,501,502,503,504];
var TO = ['adwordsspreadsheet@gmail.com'/*,''*/];
var SUBJECT = 'Broken Url Report - ' + _getDateString();
var HTTP_OPTIONS = {
muteHttpExceptions:true
};
//Let's look at ads and keywords for urls
var iters = [
//For Ad Level Urls
AdWordsApp.ads()
.withCondition("Status = 'ENABLED'")
.withCondition("AdGroupStatus = 'ENABLED'")
.withCondition("CampaignStatus = 'ENABLED'")
.withCondition("Type = 'TEXT_AD'")
.get(),
//For Keyword Level Urls
AdWordsApp.keywords()
.withCondition("Status = 'ENABLED'")
.withCondition("DestinationUrl != ''")
.withCondition("AdGroupStatus = 'ENABLED'")
.withCondition("CampaignStatus = 'ENABLED'")
.get()
];
var already_checked = {}; 
var bad_entities = [];
for(var x in iters) {
var iter = iters[x];
while(iter.hasNext()) {
var entity = iter.next();
if(entity.getDestinationUrl() == null) { continue; }
var url = entity.getDestinationUrl();
if(url.indexOf('{') >= 0) {
//Let's remove the value track parameters
url = url.replace(/\{[0-9a-zA-Z]+\}/g,'');
}
if(already_checked[url]) { continue; }
var response_code;
try {
Logger.log("Testing url: "+url);
response_code = UrlFetchApp.fetch(url, HTTP_OPTIONS).getResponseCode();
} catch(e) {
//Something is wrong here, we should know about it.
bad_entities.push({e : entity, code : -1});
}
if(BAD_CODES.indexOf(response_code) >= 0) {
//This entity has an issue.  Save it for later. 
bad_entities.push({e : entity, code : response_code});
}
already_checked[url] = true;
}
}
var column_names = ['Type','CampaignName','AdGroupName','Id','Headline/KeywordText','ResponseCode','DestUrl'];
var attachment = column_names.join(",")+"\n";
for(var i in bad_entities) {
attachment += _formatResults(bad_entities[i],",");
}
if(bad_entities.length > 0) {
var options = { attachments: [Utilities.newBlob(attachment, 'text/csv', 'bad_urls_'+_getDateString()+'.csv')] };
var email_body = "There are " + bad_entities.length + " urls that are broken. See attachment for details.";
for(var i in TO) {
MailApp.sendEmail(TO[i], SUBJECT, email_body, options);
}
}  
}
//Formats a row of results separated by SEP
function _formatResults(entity,SEP) {
var e = entity.e;
if(typeof(e['getHeadline']) != "undefined") {
//this is an ad entity
return ["Ad",
e.getCampaign().getName(),
e.getAdGroup().getName(),
e.getId(),
e.getHeadline(),
entity.code,
e.getDestinationUrl()
].join(SEP)+"\n";
} else {
// and this is a keyword
return ["Keyword",
e.getCampaign().getName(),
e.getAdGroup().getName(),
e.getId(),
e.getText(),
entity.code,
e.getDestinationUrl()
].join(SEP)+"\n";
}
}
//Helper function to format todays date
function _getDateString() {
return Utilities.formatDate((new Date()), AdWordsApp.currentAccount().getTimeZone(), "yyyy-MM-dd");
}

Fixing Capitalization Errors in Your Ads| Tự động sửa lỗi viết hoa

//-----------------------------------
// Fix Ads with EXCESSIVE CAPITALIZATION
// Created By: Russ Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
var find_caps = /[A-Z]{3,}/g;
var SEP = '~~@~~'; // this needs to be something you would never put in your ads.
var ad_iter = AdWordsApp.ads().withCondition("ApprovalStatus = 'DISAPPROVED'").get();
while(ad_iter.hasNext()) {
var ad = ad_iter.next();
var old_ad_cnt = get_ad_count(ad.getAdGroup());
var old_ad_str = [ad.getHeadline(),ad.getDescription1(),ad.getDescription2(),ad.getDisplayUrl()].join(SEP);
var new_ad_str = old_ad_str;
Logger.log("Before:"+old_ad_str);
var m = "";
while((m = find_caps.exec(new_ad_str)) != null) {
new_ad_str = replace_all(new_ad_str,m[0],init_cap(m[0]),false);
}
Logger.log("After:"+new_ad_str);
if(old_ad_str != new_ad_str) {
var [new_headline,new_desc1,new_desc2,new_disp_url] = new_ad_str.split(SEP);
ad.getAdGroup().createTextAd(new_headline, new_desc1, new_desc2, new_disp_url, ad.getDestinationUrl());
var new_ad_cnt = get_ad_count(ad.getAdGroup());
if(new_ad_cnt == (old_ad_cnt+1)) {
ad.remove();
}
} else {
Logger.log("Skipping because no changes were made."); 
}
}
function init_cap(s) {
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
}
// This function was adapted from: http://dumpsite.com/forum/index.php?topic=4.msg8#msg8 
function replace_all(original,str1, str2, ignore) {
return original.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
}
function get_ad_count(ad_group) {
var ad_iter = ad_group.ads().get();
var new_ad_cnt = 0;
while(ad_iter.hasNext()) {
ad_iter.next();
new_ad_cnt++;
}
return new_ad_cnt;
}
}

Update Your Bids from a Google Spreadsheet|Điều chỉnh giá thầu qua Spreadsheet

****************************************
* Update Bids Using a Google Spreadsheet
* Version 1.1
* Created By: Russ Savage
* FreeAdWordsScripts.com
****************************************/
function main() {
var SPREADSHEET_URL = " https://docs.google.com/spreadsheet/ccc?key=0Aotb6eheEOpodEhDM2hqQmhfeTdHT3BLMl80aDRxTkE";
var spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
var sheet = spreadsheet.getSheetByName('KeywordBids');
var data = sheet.getRange("A:E").getValues();
var kwBidHash = {};
for(var i in data) {
if(i == 0) { continue; }
if(data[i][0] === '') { break; }
var kwKey = Utilities.base64Encode([data[i][0],data[i][1],data[i][2]].join('~~!~~'));
kwBidHash[kwKey] = data[i];
}
var kwIter = AdWordsApp.keywords()
.withCondition("Status = ENABLED")
.get();
while(kwIter.hasNext()) {
var kw = kwIter.next();
var campName = kw.getCampaign().getName();
var kwKey = Utilities.base64Encode([campName,kw.getText(),kw.getMatchType()].join('~~!~~'));
if(kwBidHash[kwKey]) {
if(kwBidHash[kwKey][3] === "FIXED") {
kw.setMaxCpc(kwBidHash[kwKey][4]);
}else{
kw.setMaxCpc(kw.getMaxCpc() * (1+kwBidHash[kwKey][4]));
}
}
}
}

Update Ad Params from Google Spreadsheet|Điều chỉnh giá thầu cho từ khóa qua Spreadsheet


/************************************************
* Update Ad Params Using a Google Spreadsheet
* Version 1.1
* ChangeLog v1.1
*  - Added the ability to enable param1 or 2 individually
*  - Looks for Keywords on all sheets
*  - Runs much faster
* Created By: Russ Savage
* FreeAdWordsScripts.com
************************************************/
var SPREADSHEET_URL = "Thttps://docs.google.com/spreadsheets/d/1n7JlTiuofHwAXoGVVCPBrH8AQKXrKNnKLnTzegLmoCA/edit#gid=0";
var SET_PARAM1 = true;
var SET_PARAM2 = false;
var DATA_RANGE = 'A:E'; // A - CampaignName, B - AdGroupName, 
// C - Keyword, D - Param1, E - Param2
function main() {
var spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
var allSheets = spreadsheet.getSheets();
var allData = [];
for(var i in allSheets) {
var sheet = allSheets[i];
var data = sheet.getRange(DATA_RANGE).getValues();
data.shift(); //get rid of headers
allData = allData.concat(data);
}
var allDataHash = {};
for(var i in allData) {
var row = allData[i];
if(row[0] === '') { continue; }
var rowKey = [row[0],row[1],row[2]].join('~~!~~');
allDataHash[rowKey] = { param1 : row[3], param2: row[4] };
}
var kwIter = AdWordsApp.keywords()
.withCondition('CampaignStatus = ENABLED')
.withCondition('AdGroupStatus = ENABLED')
.withCondition('Status = ENABLED')
.get();
while(kwIter.hasNext()) { 
var kw = kwIter.next();
var campName = kw.getCampaign().getName();
var adGroupName = kw.getAdGroup().getName();
var rowKey = [campName,adGroupName,kw.getText()].join('~~!~~');
if(allDataHash[rowKey]) {
if(SET_PARAM1) { kw.setAdParam(1, allDataHash[rowKey].param1); }
if(SET_PARAM2) { kw.setAdParam(2, allDataHash[rowKey].param2); }
}
}
}

Automatically Pause Ads with Low CTR


/-----------------------------------
// Pause Ads with Low CTR
// Created By: Russ Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
// Let's start by getting all of the adGroups that are active
var ag_iter = AdWordsApp.adGroups()
.withCondition("Status = ENABLED")
.get();
// Then we will go through each one
while (ag_iter.hasNext()) {
var ag = ag_iter.next();
var ad_iter = ag.ads()
.withCondition("Status = ENABLED")
.forDateRange("ALL_TIME")
.orderBy("Ctr DESC")
.get();
var ad_array = new Array();
while(ad_iter.hasNext()) {
ad_array.push(ad_iter.next());
}
if(ad_array.length > 1) {
for(var i = 1; i < ad_array.length; i++) {
ad_array[i].pause(); //or .remove(); to delete them 
}
}
}
}

Delete All Disapproved Ads in an Account

//-----------------------------------
// Delete Ads That Are Disapproved
// Created By: Russ Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
// Let's start by getting all of the ad that are disapproved
var ad_iter = AdWordsApp.ads()
.withCondition("ApprovalStatus != APPROVED")
.get();
// Then we will go through each one
while (ad_iter.hasNext()) {
var ad = ad_iter.next();
// now we delete the ad
Logger.log("Deleteing ad: " + ad.getHeadline());
ad.remove();
}
}

Pause All Keywords With No Impressions

/*********************************************
* Pause Keywords With No Impressions All Time
* Version 1.1
* Changelog v1.1
*   - Updated for speed and added comments 
* Created By: Russ Savage
* FreeAdWordsScripts.com
**********************************************/
var TO_NOTIFY = "your_email@domain.com";
function main() {
// Let's start by getting all of the keywords with no impressions
var kwIter = AdWordsApp.keywords()
.withCondition("Impressions = 0") // could be "Clicks = 0" also
.forDateRange("ALL_TIME") // could use a specific date range like "20130101","20131231"
.withCondition("Status = ENABLED")
.withCondition("CampaignStatus = ENABLED")
.withCondition("AdGroupStatus = ENABLED")
.get();
// It is much faster to store all the keywords you want to process
// and then make the changes all at once. This takes advantage
// of the batch processing behind the scenes.
var toPause = [];
while (kwIter.hasNext()) {
var kw = kwIter.next();
toPause.push(kw);
// This is to make sure you see things during the preview
// When you run it for real, you can remove this clause to
// increase speed.
if(AdWordsApp.getExecutionInfo().isPreview() &&
AdWordsApp.getExecutionInfo().getRemainingTime() < 10) {
break;
}
}
// Now go through each one and pause them.
for(var i in toPause) {
toPause[i].pause();
//Or you could use toPause[i].remove(); to delete the keyword altogether
}
// Sent an email to notify you of the changes
MailApp.sendEmail(TO_NOTIFY, 
"AdWords Script Paused "+toPause.length+" Keywords.", 
"Your AdWords Script paused "+toPause.length+" keywords.");
}

Advanced ad scheduling|Lịch quảng cáo

Để ý true/false cho mobi 
/*
*
* Advanced ad scheduling
*
* This script will apply ad schedules to campaigns or shopping campaigns and set
* the ad schedule bid modifier and mobile bid modifier at each hour according to
* multiplier timetables in a Google sheet.
*
* This version creates schedules with modifiers for 4 hours, then fills the rest
* of the day and the other days of the week with schedules with no modifier as a
* fail safe.
*
* Version: 3.3
* Updated 2019-08-07 to fix bug with shopping campaigns
* brainlabsdigital.com
*
*/
function main() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//Options
//The Google sheet to use
//The default value is the example sheet
var spreadsheetUrl = "https://docs.google.com/spreadsheets/d/1vp_7h_BoWkcMcT5Y8yxlzjkC0iEze0xX_r6FTLjwnhA/edit#gid=0";
//Shopping or regular campaigns
//Use true if you want to run script on shopping campaigns (not regular campaigns).
//Use false for regular campaigns.
var shoppingCampaigns = false;
//Use true if you want to set mobile bid adjustments as well as ad schedules.
//Use false to just set ad schedules.
var runMobileBids = false;
//Optional parameters for filtering campaign names. The matching is case insensitive.
//Select which campaigns to exclude e.g ["foo", "bar"] will ignore all campaigns
//whose name contains 'foo' or 'bar'. Leave blank [] to not exclude any campaigns.
var excludeCampaignNameContains = [];
//Select which campaigns to include e.g ["foo", "bar"] will include only campaigns
//whose name contains 'foo' or 'bar'. Leave blank [] to include all campaigns.
var includeCampaignNameContains = [];
//When you want to stop running the ad scheduling for good, set the lastRun
//variable to true to remove all ad schedules.
var lastRun = false;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//Initialise for use later.
var weekDays = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"];
var adScheduleCodes = [];
var campaignIds = [];
//Retrieving up hourly data
var scheduleRange = "B2:H25";
var accountName = AdWordsApp.currentAccount().getName();
var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetUrl);
var sheets = spreadsheet.getSheets();
var timeZone = AdWordsApp.currentAccount().getTimeZone();
if (timeZone === "Etc/GMT") {
timeZone = "GMT";
}
var date = new Date();
var dayOfWeek = parseInt(Utilities.formatDate(date, timeZone, "uu"), 10) - 1;
var hour = parseInt(Utilities.formatDate(date, timeZone, "HH"), 10);
var sheet = sheets[0];
var data = sheet.getRange(scheduleRange).getValues();
//This hour's bid multiplier.
var thisHourMultiplier = data[hour][dayOfWeek];
var lastHourCell = "I2";
sheet.getRange(lastHourCell).setValue(thisHourMultiplier);
//The next few hours' multipliers
var timesAndModifiers = [];
var otherDays = weekDays.slice(0);
for (var h=0; h<5; h++) { var newHour = (hour + h)%24; if (hour + h > 23) {
var newDay = (dayOfWeek + 1)%7;
} else {
var newDay = dayOfWeek;
}
otherDays[newDay] = "-";
if (h<4) {
// Use the specified bids for the next 4 hours
var bidModifier = data[newHour][newDay];
if (isNaN(bidModifier) || (bidModifier < -0.9 && bidModifier > -1) || bidModifier > 9) {
Logger.log("Bid modifier '" + bidModifier + "' for " + weekDays[newDay] + " " + newHour + " is not valid.");
timesAndModifiers.push([newHour, newHour+1, weekDays[newDay], 0]);
} else if (bidModifier != -1 && bidModifier.length != 0) {
timesAndModifiers.push([newHour, newHour+1, weekDays[newDay], bidModifier]);
}
} else {
// Fill in the rest of the day with no adjustment (as a back-up incase the script breaks)
timesAndModifiers.push([newHour, 24, weekDays[newDay], 0]);
}
}
if (hour>0) {
timesAndModifiers.push([0, hour, weekDays[dayOfWeek], 0]);
}
for (var d=0; d<otherDays.length; d++) {
if (otherDays[d] != "-") {
timesAndModifiers.push([0, 24, otherDays[d], 0]);
}
}
//Pull a list of all relevant campaign IDs in the account.
var campaignSelector = ConstructIterator(shoppingCampaigns);
for(var i = 0; i < excludeCampaignNameContains.length; i++){
campaignSelector = campaignSelector.withCondition('Name DOES_NOT_CONTAIN_IGNORE_CASE "' + excludeCampaignNameContains[i] + '"');
}
campaignSelector = campaignSelector.withCondition("Status IN [ENABLED,PAUSED]");
var campaignIterator = campaignSelector.get();
while(campaignIterator.hasNext()){
var campaign = campaignIterator.next();
var campaignName = campaign.getName();
var includeCampaign = false;
if(includeCampaignNameContains.length === 0){
includeCampaign = true;
}
for(var i = 0; i < includeCampaignNameContains.length; i++){
var index = campaignName.toLowerCase().indexOf(includeCampaignNameContains[i].toLowerCase());
if(index !== -1){
includeCampaign = true;
break;
}
}
if(includeCampaign){
var campaignId = campaign.getId();
campaignIds.push(campaignId);
}
}
//Return if there are no campaigns.
if(campaignIds.length === 0){
Logger.log("There are no campaigns matching your criteria.");
return;
}
//Remove all ad scheduling for the last run.
if(lastRun){
checkAndRemoveAdSchedules(campaignIds, [], shoppingCampaigns);
return;
}
// Change the mobile bid adjustment
if(runMobileBids){
if (sheets.length < 2) {
Logger.log("Mobile ad schedule sheet was not found in the Google spreadsheet.");
} else {
var sheet = sheets[1];
var data = sheet.getRange(scheduleRange).getValues();
var thisHourMultiplier_Mobile = data[hour][dayOfWeek];
if (thisHourMultiplier_Mobile.length === 0) {
thisHourMultiplier_Mobile = -1;
}
if (isNaN(thisHourMultiplier_Mobile) || (thisHourMultiplier_Mobile < -0.9 && thisHourMultiplier_Mobile > -1) || thisHourMultiplier_Mobile > 3) {
Logger.log("Mobile bid modifier '" + thisHourMultiplier_Mobile + "' for " + weekDays[dayOfWeek] + " " + hour + " is not valid.");
thisHourMultiplier_Mobile = 0;
}
var totalMultiplier = ((1+thisHourMultiplier_Mobile)*(1+thisHourMultiplier))-1;
sheet.getRange("I2").setValue(thisHourMultiplier_Mobile);
sheet.getRange("T2").setValue(totalMultiplier);
ModifyMobileBidAdjustment(campaignIds, thisHourMultiplier_Mobile);
}
}
// Check the existing ad schedules, removing those no longer necessary
var existingSchedules = checkAndRemoveAdSchedules(campaignIds, timesAndModifiers, shoppingCampaigns);
// Add in the new ad schedules
AddHourlyAdSchedules(campaignIds, timesAndModifiers, existingSchedules, shoppingCampaigns);
}
/**
* Function to add ad schedules for the campaigns with the given IDs, unless the schedules are
* referenced in the existingSchedules array. The scheduling will be added as a hour long periods
* as specified in the passed parameter array and will be given the specified bid modifier.
*
* @param array campaignIds array of campaign IDs to add ad schedules to
* @param array timesAndModifiers the array of [hour, day, bid modifier] for which to add ad scheduling
* @param array existingSchedules array of strings identifying already existing schedules.
* @param bool shoppingCampaigns using shopping campaigns?
* @return void
*/
function AddHourlyAdSchedules(campaignIds, timesAndModifiers, existingSchedules, shoppingCampaigns){
// times = [[hour,day],[hour,day]]
var campaignIterator = ConstructIterator(shoppingCampaigns)
.withIds(campaignIds)
.get();
while(campaignIterator.hasNext()){
var campaign = campaignIterator.next();
for(var i = 0; i < timesAndModifiers.length; i++){ if (existingSchedules.indexOf( timesAndModifiers[i][0] + "|" + (timesAndModifiers[i][1]) + "|" + timesAndModifiers[i][2] + "|" + Utilities.formatString("%.2f",(timesAndModifiers[i][3]+1)) + "|" + campaign.getId()) > -1) {
continue;
}
campaign.addAdSchedule({
dayOfWeek: timesAndModifiers[i][2],
startHour: timesAndModifiers[i][0],
startMinute: 0,
endHour: timesAndModifiers[i][1],
endMinute: 0,
bidModifier: Math.round(100*(1+timesAndModifiers[i][3]))/100
});
}
}
}
/**
* Function to remove ad schedules from all campaigns referenced in the passed array
* which do not correspond to schedules specified in the passed timesAndModifiers array.
*
* @param array campaignIds array of campaign IDs to remove ad scheduling from
* @param array timesAndModifiers array of [hour, day, bid modifier] of the wanted schedules
* @param bool shoppingCampaigns true if running on Shopping campaigns, false if Search/Display
* @return array existingWantedSchedules array of strings identifying the existing undeleted schedules
*/
function checkAndRemoveAdSchedules(campaignIds, timesAndModifiers, shoppingCampaigns) {
var adScheduleIds = [];
var report = AdWordsApp.report(
'SELECT CampaignId, Id ' +
'FROM CAMPAIGN_AD_SCHEDULE_TARGET_REPORT ' +
'WHERE CampaignId IN ["' + campaignIds.join('","')  + '"]'
);
var rows = report.rows();
while(rows.hasNext()){
var row = rows.next();
var adScheduleId = row['Id'];
var campaignId = row['CampaignId'];
if (adScheduleId == "--") {
continue;
}
adScheduleIds.push([campaignId,adScheduleId]);
}
var chunkedArray = [];
var chunkSize = 10000;
for(var i = 0; i < adScheduleIds.length; i += chunkSize){
chunkedArray.push(adScheduleIds.slice(i, i + chunkSize));
}
var wantedSchedules = [];
var existingWantedSchedules = [];
for (var j=0; j<timesAndModifiers.length; j++) {
wantedSchedules.push(timesAndModifiers[j][0] + "|" + (timesAndModifiers[j][1]) + "|" + timesAndModifiers[j][2] + "|" + Utilities.formatString("%.2f",timesAndModifiers[j][3]+1));
}
for(var i = 0; i < chunkedArray.length; i++){ var unwantedSchedules = []; var adScheduleIterator = AdWordsApp.targeting() .adSchedules() .withIds(chunkedArray[i]) .get(); while (adScheduleIterator.hasNext()) { var adSchedule = adScheduleIterator.next(); var key = adSchedule.getStartHour() + "|" + adSchedule.getEndHour() + "|" + adSchedule.getDayOfWeek() + "|" + Utilities.formatString("%.2f",adSchedule.getBidModifier()); if (wantedSchedules.indexOf(key) > -1) {
if (shoppingCampaigns) {
var campaign = adSchedule.getShoppingCampaign();
} else {
var campaign = adSchedule.getCampaign();
}
existingWantedSchedules.push(key + "|" + campaign.getId());
} else {
unwantedSchedules.push(adSchedule);
}
}
for(var j = 0; j < unwantedSchedules.length; j++){
unwantedSchedules[j].remove();
}
}
return existingWantedSchedules;
}
/**
* Function to construct an iterator for shopping campaigns or regular campaigns.
*
* @param bool shoppingCampaigns Using shopping campaigns?
* @return AdWords iterator Returns the corresponding AdWords iterator
*/
function ConstructIterator(shoppingCampaigns){
if(shoppingCampaigns === true){
return AdWordsApp.shoppingCampaigns();
}
else{
return AdWordsApp.campaigns();
}
}
/**
* Function to set a mobile bid modifier for a set of campaigns
*
* @param array campaignIds An array of the campaign IDs to be affected
* @param Float bidModifier The multiplicative mobile bid modifier
* @return void
*/
function ModifyMobileBidAdjustment(campaignIds, bidModifier){
var platformIds = [];
var newBidModifier = Math.round(100*(1+bidModifier))/100;
for(var i = 0; i < campaignIds.length; i++){
platformIds.push([campaignIds[i],30001]);
}
var platformIterator = AdWordsApp.targeting()
.platforms()
.withIds(platformIds)
.get();
while (platformIterator.hasNext()) {
var platform = platformIterator.next();
platform.setBidModifier(newBidModifier);
}
}

Disable Ads and Keywords For Out of Stock Items

/************************************
* Item Out Of Stock Checker
* Version 1.2
* ChangeLog v1.2
*  - ONLY_ACTIVE is used to filter campaigns and adgroups only. All Keywords and Ads in the AdGroups will
*    be checked which solves the "once disabled, always disabled" issue.
*  - Updated call to get the Final Urls. Now calls getFinalUrl and getMobileFinalUrl instead of getDestinationUrl
*  - OUT_OF_STOCK_TEXTS can now contain multiple things to check for.
*  - If the CAMPAIGN_LABEL does not exist, it is ignored with a warning.
* ChangeLog v1.1 - Filtered out deleted Campaigns and AdGroups
* Created By: Russ Savage
* FreeAdWordsScripts.com
***********************************/
var URL_LEVEL = 'Ad'; // or Keyword
var ONLY_ACTIVE = true; // set to false to check keywords or ads in all campaigns (paused and active)
var CAMPAIGN_LABEL = ''; // set this if you want to only check campaigns with this label
var STRIP_QUERY_STRING = true; // set this to false if the stuff that comes after the question mark is important
var WRAPPED_URLS = true; // set this to true if you use a 3rd party like Marin or Kenshoo for managing you account
// This is the specific text (or texts) to search for 
// on the page that indicates the item 
// is out of stock. If ANY of these match the html
// on the page, the item is considered "out of stock"
var OUT_OF_STOCK_TEXTS = [
'The Text That Identifies An Out Of Stock Item Goes Here',
'Another string might go here but does not need to'
];
function main() {
var alreadyCheckedUrls = {};
var iter = buildSelector().get();
while(iter.hasNext()) {
var entity = iter.next();
var urls = [];
if(entity.urls().getFinalUrl()) {
urls.push(entity.urls().getFinalUrl());
}
if(entity.urls().getMobileFinalUrl()) {
urls.push(entity.urls().getMobileFinalUrl());
}
for(var i in urls) {
var url = cleanUrl(urls[i]);
if(alreadyCheckedUrls[url]) {
if(alreadyCheckedUrls[url] === 'out of stock') {
entity.pause();
} else {
entity.enable();
}
} else {
var htmlCode;
try {
htmlCode = UrlFetchApp.fetch(url).getContentText();
} catch(e) {
Logger.log('There was an issue checking:'+url+', Skipping.');
continue;
}
var did_pause = false;
for(var x in OUT_OF_STOCK_TEXTS) {
if(htmlCode.indexOf(OUT_OF_STOCK_TEXTS[x]) >= 0) {
alreadyCheckedUrls[url] = 'out of stock';
entity.pause();
did_pause = true;
break;
}
}
if(!did_pause) {
alreadyCheckedUrls[url] = 'in stock';
entity.enable();
}
}
Logger.log('Url: '+url+' is '+alreadyCheckedUrls[url]);
}
}
}
function cleanUrl(url) {
if(WRAPPED_URLS) {
url = url.substr(url.lastIndexOf('http'));
if(decodeURIComponent(url) !== url) {
url = decodeURIComponent(url);
}
}
if(STRIP_QUERY_STRING) {
if(url.indexOf('?')>=0) {
url = url.split('?')[0];
}
}
if(url.indexOf('{') >= 0) {
//Let's remove the value track parameters
url = url.replace(/\{[0-9a-zA-Z]+\}/g,'');
}
return url;
}
function buildSelector() {
var selector = (URL_LEVEL === 'Ad') ? AdWordsApp.ads() : AdWordsApp.keywords();
selector = selector.withCondition('CampaignStatus != DELETED').withCondition('AdGroupStatus != DELETED');
if(ONLY_ACTIVE) {
selector = selector.withCondition('CampaignStatus = ENABLED');
if(URL_LEVEL !== 'Ad') {
selector = selector.withCondition('AdGroupStatus = ENABLED');
}
}
if(CAMPAIGN_LABEL) {
if(AdWordsApp.labels().withCondition("Name = '"+CAMPAIGN_LABEL+"'").get().hasNext()) {
var label = AdWordsApp.labels().withCondition("Name = '"+CAMPAIGN_LABEL+"'").get().next();
var campIter = label.campaigns().get();
var campaignNames = [];
while(campIter.hasNext()) {
campaignNames.push(campIter.next().getName());
}
selector = selector.withCondition("CampaignName IN ['"+campaignNames.join("','")+"']");
} else {
Logger.log('WARNING: Campaign label does not exist: '+CAMPAIGN_LABEL);
}
}
return selector;
}

Mã chuyển đổi theo đơn hàng


Thư viện scripts ads

https://developers.google.com/google-ads/scripts/docs/reference/adsapp/adsapp_adgroup

Thư viện mẫu QC

https://developers.google.com/adwords/api/docs/guides/template-ads



Sản phẩm

Bài viết liên quan