AdWords Script: Keyword Bidding by Search Lost IS (rank)
This script changes the bids of keywords of specific campaigns/ad-groups so they appear in target positions. It runs every 3 days, so it always uses 3 day data but you can change this based on your campaigns data history.
Search Lost impressions share (rank) is the estimated percentage of impressions on the Search Network that your ads didn’t receive due to poor Ad Rank.
What it means: A high Search Lost IS (rank) means there were many times your ad was eligible to show on the Search Network but didn’t because its Ad Rank was too low. Search Lost IS (rank) is updated once a day.
What to do: If you’re seeing a high Search Lost IS (rank), try increasing your bid or improving your Quality Score. If you’re not seeing a number at all, it could be because you ran out of budget during this date range.
The changes are limited to 5% of the current bid, and you can set maximum CPC bids – so you’re still in complete control.
How to use the script:
1. Label your campaigns and ad-groups to show Search Lost Is Rank goal: for example label campaigns you want “Lost IS Rank 10%″ to get closer to 10%.
2. Copy the script below. Go to your AdWords account, into “Bulk operations” and then into “Scripts”. Make a new Script and paste the code in.
3. Set the options at the top of the code:
- CAMPAIGN_LABEL Select campaign you want the script to run on. Leave blank to impact all campaigns.
- ADGROUP_LABEL Select ad-group you want the script to run on. Leave blank to impact all ad-groups.
- TARGET_SEARCH_IS_RANK set target rank % (10% and up)
- MIN_CONVERTED_CLICKS By default it set to zero, if you want the script to only run on keywords that have conversion history, change the number to 1 to impact all keywords that converted at least once in the past 3 days.
- BID_INCREASE_PCT increases bids by % until a desired Search Lost IS Rank % is reached, for example: <10%.
- LAST_N_DAYS number of days the scripts looks back for data.
- MAX_CPC sets the max cost per click and stops once hits this threshold.
- Save and preview the script (giving authorization when asked). This will show you the first 100 changes the script will make. If everything looks good, run the script for real!
- Create a schedule so that the script runs everyday. This means the script can constantly check new data and keep up with the ever changing auction landscape.
AdWords Script:
/**
*
* Keyword Bidding By Search Lost IS Rank Tool
*
* This script changes keyword bids so that they target specified Search Lost IS Rank %,
* based on recent performance.
*
* Version: 1.0
* Google AdWords Script maintained on geoklix.com
*
**/
// Label to filter Campaigns/AdGroups
var CAMPAIGN_LABEL = ”;
var ADGROUP_LABEL = ”;
var TARGET_SEARCH_IS_RANK = 10; // 10%
//Converted Clicks Threshold
var MIN_CONVERTED_CLICKS = 0;
// How much to adjust the bids.
var BID_INCREASE_PCT = 5; // 5% increase
// Number of Days to look back
var LAST_N_DAYS = 3; // 3 days
// Max Cpc Thresholds
var MAX_CPC = 5; // $5
function main() {
log(‘Started’);
var agIds = [];
if(CAMPAIGN_LABEL.length || ADGROUP_LABEL.length) {
agIds = findAdGroups();
if(agIds.length == 0) {
log(‘0 Active Campaigns/AdGroups Found’);
return;
}
}
var dateTo = getAdWordsFormattedDate(0, ‘yyyyMMdd’);
var dateFrom = getAdWordsFormattedDate(LAST_N_DAYS, ‘yyyyMMdd’);
var DATE_RANGE = dateFrom + ‘,’ + dateTo;
var kwIds = collectKeywords(agIds, DATE_RANGE);
if(kwIds.length == 0) {
log(‘No Data Found’);
return;
}
log(‘Increasing Bids’);
var FACTOR = (1 + BID_INCREASE_PCT/100);
var kws = AdWordsApp.keywords()
.withIds(kwIds)
.withCondition(‘MaxCpc < ‘ + MAX_CPC) .get(); log(‘Keywords Found: ‘ + kws.totalNumEntities()); while (kws.hasNext()) { var kw = kws.next(); var newCpc = kw.bidding().getCpc() * FACTOR; // Apply Stop Limit on New Cpc if(newCpc > MAX_CPC) { newCpc = MAX_CPC; }
//Update Cpc
kw.bidding().setCpc(newCpc);
}
log(‘Finished’);
}
function collectKeywords(agIds,DATE_RANGE) {
var OPTIONS = { includeZeroImpressions : false };
var cols = [‘AdGroupId’,’Id’,’Impressions’,’Clicks’,’SearchRankLostImpressionShare’];
var report = ‘KEYWORDS_PERFORMANCE_REPORT’;
var query = [‘select’,cols.join(‘,’),’from’,report,
‘where CampaignStatus = ENABLED AND AdGroupStatus = ENABLED AND Status = ENABLED’,
‘and ConvertedClicks >= ‘ + MIN_CONVERTED_CLICKS,
agIds.length == 0 ? ” : ‘and AdGroupId IN [‘ + agIds.join(‘,’) + ‘]’,
‘and SearchRankLostImpressionShare > ‘ + (TARGET_SEARCH_IS_RANK/100),
‘during’,DATE_RANGE].join(‘ ‘);
var reportIter = AdWordsApp.report(query, OPTIONS).rows();
var kwIds = [];
while(reportIter.hasNext()) {
var reportRow = reportIter.next();
kwIds.push([reportRow.AdGroupId, reportRow.Id]);
}
return kwIds;
}
function findAdGroups() {
var campIds = [];
var agIds = [];
if(CAMPAIGN_LABEL.length > 0) {
var camps = AdWordsApp.campaigns()
.withCondition(‘Status = ENABLED’)
.withCondition(‘LabelNames CONTAINS_ANY [“‘ + CAMPAIGN_LABEL + ‘”]’)
.get();
while(camps.hasNext()) {
campIds.push(camps.next().getId());
}
if(campIds.length == 0) {
log(‘0 Campaigns Found with label: ‘ + CAMPAIGN_LABEL);
return agIds;
}
}
var adGroups = AdWordsApp.aGroups()
.withCondition(‘Status = ENABLED’)
.withCondition(‘CampaignStatus = ENABLED’)
if(campIds.length > 0) {
adGroups.withCondition(‘CampaignId IN [‘ + campIds.join(‘,’) + ‘]’)
}
if(ADGROUP_LABEL.length > 0) {
adGroups.withCondition(‘LabelNames CONTAINS_ANY [“‘ + ADGROUP_LABEL + ‘”]’)
}
adGroups = adGroups.get();
while(adGroups.hasNext()){
agIds.push(adGroups.next().getId());
}
return agIds;
}
/**
* Get AdWords Formatted date for n days back
* @param {int} d – Numer of days to go back for start/end date
* @return {String} – Formatted date yyyyMMdd
**/
function getAdWordsFormattedDate(d, format){
var date = new Date();
date.setDate(date.getDate() – d);
return Utilities.formatDate(date,AdWordsApp.currentAccount().getTimeZone(),format);
}
function log(msg) {
var time = Utilities.formatDate(new Date(),AdWordsApp.currentAccount().getTimeZone(), ‘yyyy-MM-dd HH:mm:ss.SSS’);
Logger.log(time + ‘ – ‘ + msg);
}