显示带有标签的帖子 帐户维护. 显示所有帖子
显示带有标签的帖子 帐户维护. 显示所有帖子

2013年11月30日,星期六

使用AdWords脚本的AdWords帐户审核清单

我正在浏览一些旧的 WordStream博客文章 并从Phil Kowalski注意到了 AdWords帐户审核清单。大部分工作似乎可以使用AdWords脚本自动完成,因此我想尝试一下。

以下脚本运行尽可能多的检查,并尝试报告要首先检出的区域。这对于确保您接管的帐户至少具有适用的基本知识很有用。

要查看结果,请在您的帐户中运行脚本,然后单击“查看详细信息”链接,然后单击“日志”按钮。您应该看到该脚本找到的所有警告。尝试一下,让我知道您可能会添加哪些其他检查。

谢谢,
拉斯

/************************************
* AdWords帐户审核清单
* Version 1.1
* ChangeLog v1.1 - Fixed issue with extension selector.
* Based on the blog post by Phil Kowalski
* http://www.wordstream.com/blog/ws/2013/07/02/adwords-account-audit-checklist
* Created By: 拉斯 Savage
* FreeAdWordsScripts.com
************************************/
function main() {
  //1. Campaigns
  //  a. Target the right locations
  var includedLocList = ['United States','Canada']; // <-- the list of places your 运动s should be targeting
  verifyTargetedLocations(includedLocList);
  
  var excludedLocList = ['Europe']; // <-- the list of places your 运动s should be excluding
  verifyExcludedLocations(excludedLocList);
  
  //  b. Language - Can't be done using 剧本 yet :(
  //  c. 搜索 vs Display
  verifySearchAndDisplay();
  
  //  d. Check Mobile Strategy
  verifyMobileModifiers();
  
  //2. AdGroups
  //  a. Check for AdGroups with more than 20-30 关键字
  var ADGROUP_SIZE = 25; // <-- this is the max number of 关键字 you want in an AdGroup
  verifyAdGroupSize(ADGROUP_SIZE);
  
  //  b. Check for topic. Difficult to do with 剧本
  //  c. Check for  广告 
  var NUMBER_OF_ADS = 3; // <-- this is the minimum number of  广告  in an AdGroup
  verifyAdGroupNumberOfAds(NUMBER_OF_ADS);
  
  //3. Keywords
  //  a. Check for MatchTypes
  printMatchTypes();
  
  //4. 搜索 Queries
  //  This analysis is probably worth it's own script
  
  //5. Other
  //  a. Conversion Tracking
  verifyConversionTracking();
  
  //  b. AdExtensions
  verifyAdExtensions();
}

function verifyConversionTracking() {
  //Assume that if the account has not had a conversion in 7 days, something is wrong.
  var campsWithConversions = AdWordsApp.campaigns()
    .withCondition('Status = ENABLED')
    .forDateRange('LAST_7_DAYS')
    .withCondition('Conversions > 0')
    .get().totalNumEntities();
  if(campsWithConversions == 0) {
    warn('Account is probably missing conversion tracking.');
  }
}

function verifyAdExtensions() {
  var campIter = AdWordsApp.campaigns().withCondition('Status = ENABLED').get();
  while(campIter.hasNext()) {
    var camp = campIter.next();
    var 电话NumExtCount = camp.extensions().phoneNumbers().get().totalNumEntities();
    if(phoneNumExtCount == 0) {
      warn('Campaign: "'+camp.getName()+'" is missing 电话 number extensions.');
    }
    var siteLinksExtCount = camp.extensions().sitelinks().get().totalNumEntities();
    if(siteLinksExtCount < 6) {
      warn('Campaign: "'+camp.getName()+'" could use more site links. Currently has: '+siteLinksExtCount);
    }
    var mobileAppsExtCount = camp.extensions().mobileApps().get().totalNumEntities();
    if(mobileAppsExtCount == 0) {
      warn('Campaign: "'+camp.getName()+'" is missing mobile apps extension.');
    }
  }
}

function printMatchTypes() {
  var numBroad = AdWordsApp.keywords()
    .withCondition('Status = ENABLED')
    .withCondition('AdGroupStatus = ENABLED')
    .withCondition('CampaignStatus = ENABLED')
    .withCondition('KeywordMatchType = BROAD')
    .get().totalNumEntities();
  var numPhrase = AdWordsApp.keywords()
    .withCondition('Status = ENABLED')
    .withCondition('AdGroupStatus = ENABLED')
    .withCondition('CampaignStatus = ENABLED')
    .withCondition('KeywordMatchType = PHRASE')
    .get().totalNumEntities();
  var numExact = AdWordsApp.keywords()
    .withCondition('Status = ENABLED')
    .withCondition('AdGroupStatus = ENABLED')
    .withCondition('CampaignStatus = ENABLED')
    .withCondition('KeywordMatchType = EXACT')
    .get().totalNumEntities();
  var total = numBroad+numPhrase+numExact;
  var percBroad = Math.round(numBroad/total*100);
  var percPhrase = Math.round(numPhrase/total*100);
  var percExact = Math.round(numExact/total*100);
  info('Out of a total of: '+total+' active 关键字 in your account:');
  info('\tBroad: '+numBroad+' or '+percBroad+'%');
  info('\tPhrase: '+numPhrase+' or '+percPhrase+'%');
  info('\tExact: '+numExact+' or '+percExact+'%');
}

function verifyAdGroupNumberOfAds(requiredNumberOfAds) {
  var agIter = AdWordsApp.adGroups()
    .withCondition('Status = ENABLED')
    .withCondition('CampaignStatus = ENABLED')
    .get();
  while(agIter.hasNext()) {
    var ag = agIter.next();
    var  广告 Count = ag.ads().withCondition('Status = ENABLED').get().totalNumEntities();
    if(adCount < requiredNumberOfAds) {
      warn('Campaign: "'+ag.getCampaign().getName()+'" AdGroup: "'+ag.getName()+'" does not have enough  广告 : '+adCount);
    }
    if(adCount > (requiredNumberOfAds+2)) {
      warn('Campaign: "'+ag.getCampaign().getName()+'" AdGroup: "'+ag.getName()+'" has too many  广告 : '+adCount);
    }
  }
}

function verifyAdGroupSize(size) {
  var agIter = AdWordsApp.adGroups()
    .withCondition('Status = ENABLED')
    .withCondition('CampaignStatus = ENABLED')
    .get();
  while(agIter.hasNext()) {
    var ag = agIter.next();
    var kwSize = ag.keywords().withCondition('Status = ENABLED').get().totalNumEntities();
    if(kwSize >= size) {
      warn('Campaign: "'+ag.getCampaign().getName()+'" AdGroup: "'+ag.getName()+'" has too many 关键字: '+kwSize);
    }
  }
}

function verifyMobileModifiers() {
  var campIter = AdWordsApp.campaigns().withCondition('Status = ENABLED').get();
  while(campIter.hasNext()) {
    var camp = campIter.next();
    var desktop = camp.targeting().platforms().desktop().get().next();
    //var tablet = camp.targeting().platforms().tablet().get().next();
    var mobile = camp.targeting().platforms().mobile().get().next();
    //check for mobile modifiers
    if(desktop.getBidModifier() == 1 && mobile.getBidModifier() == 1) {
      warn('Campaign: "'+camp.getName()+'" has no mobile modifier set.');
    }
  }
}

function verifyTargetedLocations(locList) {
  var campIter = AdWordsApp.campaigns().withCondition('Status = ENABLED').get();
  while(campIter.hasNext()) {
    var camp = campIter.next();
    var locIter = camp.targeting().targetedLocations().get();
    reportOnLocations(camp,locIter,locList);
  } 
}

function verifyExcludedLocations(locList) {
  var campIter = AdWordsApp.campaigns().withCondition('Status = ENABLED').get();
  while(campIter.hasNext()) {
    var camp = campIter.next();
    var locIter = camp.targeting().excludedLocations().get();
    reportOnLocations(camp,locIter,locList);
  } 
}

function reportOnLocations(camp,locIter,locList) {
  var campLocList = [];
  while(locIter.hasNext()) {
    var loc = locIter.next();
    campLocList.push(loc.getName());
    if(!locList) {
      warn('Campaign: "'+camp.getName()+'" targeting: "'+loc.getName()+'"');
    }
  }
  if(locList && campLocList.sort() != locList.sort()) {
    for(var i in campLocList) {
      if(locList.indexOf(campLocList[i]) == -1) {
        warn('Campaign: "'+camp.getName()+'" incorrectly targeting: "'+campLocList[i]+'"');
      }
    }
    for(var i in locList) {
      if(campLocList.indexOf(locList[i]) == -1) {
        warn('Campaign: "'+camp.getName()+'" not targeting: "'+locList[i]+'"');
      }
    }
  }
}

function verifySearchAndDisplay() {
  var API_VERSION = { includeZeroImpressions : false };
  var cols = ['CampaignId','CampaignName','AdNetworkType1','Impressions'];
  var report = 'CAMPAIGN_PERFORMANCE_REPORT';
  var query = ['select',cols.join(','),'from',report,'during','LAST_30_DAYS'].join(' ');
  var results = {}; // { campId : { agId : [ row, ... ], ... }, ... }
  var reportIter = AdWordsApp.report(query, API_VERSION).rows();
  while(reportIter.hasNext()) {
    var row = reportIter.next();
    if(results[row.CampaignId]) {
      warn('Campaign: "'+row.CampaignName+'" is targeting the Display and 搜索 networks.');
    } else {
      results[row.CampaignId] = row;
    }
  }
  return results;
}

function warn(msg) {
  Logger.log('WARNING: '+msg);
}

function info(msg) {
  Logger.log(msg);
}

2013年3月4日,星期一

修复广告中的大写错误

营销人员在拥有从Feed中自动构建广告素材的系统时面临的问题之一是质量控制。最近,我遇到了一个问题,我制作了大约1000个新广告,城市名称全部为大写。 Google当然不那么喜欢,我不喜欢必须手动更新1,000个广告的想法,因此我整理了以下脚本。

该脚本会在您的帐户中运行所有被拒登的广告,并尝试在ALL CAPS中查找带有单词的广告。我不确定Google的上限是多少,但是在下面的脚本中,它将查找连续三个或三个以上大写字母的任何内容。然后替换它们,创建一个新广告,如果成功,则删除旧广告。

我在确定广告被拒登的原因时遇到了麻烦。 API中尚不提供此功能,但具有 被要求。另一个问题是,有时您创建的新广告会失败,这将导致您删除旧广告而不创建新广告。为了解决这一问题,我在制作新广告之前和之后对广告组中的广告进行了计数,以确保我的广告已创建。再说一次 发布功能请求 在adwords脚本论坛中。

谢谢,
拉斯

//-----------------------------------
// Fix Ads with EXCESSIVE CAPITALIZATION
// Created By: 拉斯 Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  var find_caps = /[A-Z]{3,}/g;
  var SEP = '[email protected]~~'; // this needs to be something you would never put in your  广告 .
  var  广告 _iter = AdWordsApp.ads().withCondition("ApprovalStatus = 'DISAPPROVED'").get();
  
  while(ad_iter.hasNext()) {
    var  广告  =  广告 _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);
       广告 .getAdGroup().createTextAd(new_headline, new_desc1, new_desc2, new_disp_url,  广告 .getDestinationUrl());
      var new_ad_cnt = get_ad_count(ad.getAdGroup());
      if(new_ad_cnt == (old_ad_cnt+1)) {
         广告 .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  广告 apted 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  广告 _iter =  广告 _group.ads().get();
    var new_ad_cnt = 0;
    while(ad_iter.hasNext()) {
       广告 _iter.next();
      new_ad_cnt++;
    }
    return new_ad_cnt;
  }
}

2012年12月11日,星期二

自动将ValueTrack参数添加到所有目标网址

今天,我们有了一个脚本,可以帮助确保您所有的关键字都已标记有适当的 价值追踪 parameters.  您可以使用它来确保将所有跟踪参数正确地添加到URL中。

您可以将自己的查询字符串参数添加到脚本顶部的映射中。 例如,如果帐户中的所有关键字都需要在其目标网址中包含参数“ channel = sem”,则可以将其添加到文件顶部的URL_PARAMS_TO_ADD映射中,并将其添加到所有网址中。

另外,我更新了脚本,允许您将帐户中想要的任何值添加到url中。如果愿意,请参见将广告系列和广告组名称添加到网址的示例。

谢谢,
拉斯

/******************************************
* Auto Add 价值追踪 (and other) Params If Not There
* Created By: 拉斯 Savage
* Version 1.1
* ChangeLog v1.1
*  - Added the ability to  广告 d function 呼叫s into the parameters to  广告 d
* FreeAdWordsScripts.com
******************************************/
function main() {
   
  var URL_PARAMS_TO_ADD = { 
    "kw" : "{keyword}",
    "crid" : "{creative}",
    "mt" : "{matchtype}",
    "ntwk" : "{network}",
    "ap" : "{adposition}",
    "dv" : "{device}",
    "dvm" : "{devicemodel}",
    //"camp" : getCampaignName,  <----- This function is defined below
    //"ag" : getAdGroupName  <----- and so is this one
  };
   
  var kw_iter = AdWordsApp.keywords()
                  .withCondition("DestinationUrl != ''")
                  .get();
  
  while(kw_iter.hasNext()) {
    var kw = kw_iter.next();
    var destUrl = kw.getDestinationUrl();
    if(!destUrl || destUrl === '') { continue; }
    var toAppend = [];
    for(var key in URL_PARAMS_TO_ADD) {
      if(destUrl.indexOf(key) >= 0) { continue; }
      var value = URL_PARAMS_TO_ADD[key];
      
      //check to see if we should 呼叫 a function
      if(typeof(value) === 'function') {
        value = encodeURI(value(kw));
      }
      toAppend.push(key+"="+value);
    }
    if(destUrl.indexOf('?') >= 0) {
      kw.setDestinationUrl(destUrl + "&"+toAppend.join('&'));
    } else {
      kw.setDestinationUrl(destUrl + "?"+toAppend.join('&'));
    }
    Logger.log(kw.getDestinationUrl());
  }
}

// As long as the function 呼叫 is passed a kw object, you can insert
// whatever value you want into the url
function getCampaignName(kw) {
  return kw.getCampaign().getName();
}

function getAdGroupName(kw) {
  return kw.getAdGroup().getName();
}

2012年12月3日,星期一

使用AdWords脚本自动执行维护任务第2部分

让我们继续自动化在中找到的维护任务 AdWords for Dummies 使用AdWords脚本。 让我们继续进行每月15号的维护。


奖励吸引廉价流量的关键字。


与上一篇文章类似,您需要设置转化跟踪才能使所有这些工作。 实际上,我们可以使用先前脚本的变体来完成此操作。 实际上,我们只是在提高出价而不是降低出价。

//-----------------------------------
// Increase Bids Cheap Conversion Keywords
// Created By: 拉斯 Savage
// FreeAdWordsScripts.com
//-----------------------------------
function main() {
  //For 关键字 with less than $5 CPC, let's pump those 竞标  up by 35%
  var AMAZING_COST_PER_CONV = 5;
  var AMAZING_BID_INCREASE_AMOUNT = .35;
  
  //For 关键字 with between $5 and $8 CPCs, we will only increase the 竞标  by 20%
  var GREAT_COST_PER_CONV = 8;
  var GREAT_BID_INCREASE_AMOUNT = .20;
  
  var kw_iter = AdWordsApp.keywords()
    .withCondition("Status = ENABLED")
    .get();
  
  while(kw_iter.hasNext()) {
    var kw = kw_iter.next();
    var kw_stats = kw.getStatsFor("LAST_30_DAYS");
    var cost = kw_stats.getCost();
    var 转换 = kw_stats.getConversions();
    if(conversions > 0) {
      var cost_per_conversion = (cost/(conversions*1.0));
      
      if(cost_per_conversion <= AMAZING_COST_PER_CONV) {
        kw.setMaxCpc(kw.getMaxCpc() * (1+AMAZING_BID_INCREASE_AMOUNT)); 
      }
      else if(cost_per_conversion <= GREAT_COST_PER_CONV) {
        kw.setMaxCpc(kw.getMaxCpc() * (1+GREAT_BID_INCREASE_AMOUNT));
      }
    }else{
      //no 转换 on this 关键词
      //we will deal with that later
      continue;
    }
  }
}
请继续关注下一期和最后一期,在此我们将删除没有转化的关键字来使我们的帐户杂乱无章。

谢谢,
拉斯