Google AdWords: как отобрать хорошие места размещения при помощи скриптов

Россия+7 (495) 960-65-87
Шрифт:
5 10019

Google Display Network (GDN) – одна из двух рекламных сетей в Google AdWords, позволяющая показывать рекламные объявления на большом количестве различных сайтов. Хоть этот инструмент и более «пассивен», чем реклама Google в поиске, он охватывает значительно большую аудиторию.

Проблема GDN

«Темной стороной» контекстной рекламы в Google Display Network является то, что ее настройка требует много времени на отбор качественных площадок. Ведь эффективной реклама будет только в том случае, если объявления будут показываться на подходящих площадках. А фильтрация тысяч площадок – это настоящая проблема для специалиста по контекстной рекламе.

Хорошая новость в том, что Google AdWords дает возможность управлять вашими рекламными кампаниями при помощи скриптов. Так что существует возможность автоматического отбора качественных площадок.

Мы решили разобраться с этим вопросом и разработать эффективное решение. За основу взяли подходы Алексея Ярошенка и Derek Martin и разработали свою методологию работы скрипта для «чистки» площадок в Google Display Network.

Решение

Для понимания, как работает наше решение в целом, разберем вначале его базовые этапы.

Начальные условия

Наш скрипт обращается к отчету по площадкам AdWords за определенный период времени и отбирает места размещения, удовлетворяющие различным условиям:

  • затраты на площадку составляют более X USD и нет конверсий;
  • стоимость конверсии с площадки больше X USD;
  • количество показов площадки больше X, CTR меньше Y и нет конверсий;
  • количество показов площадки больше X, CTR больше Y и нет конверсий.

Перечисленные выше условия могут меняться вручную в конфигурационном файле Google Spreadsheet.

Нежелательные домены

Следующая проверка отсеивает площадки без конверсий, в домене которых присутствуют нежелательные слова, и заносит их в black list.

Рис. 1.png

Рис. 1. Пример Google Spreadsheet со словами, по которым отсеиваются домены

Список исключений

Отобранные скриптом площадки заносятся в лист исключений на уровне «Shared library» в аккаунте AdWords.

Рис. 2.png

Рис. 2. Пример списков исключений в «Shared library»

Рис. 3.png

Рис. 3. Пример отчета работы скрипта в Google Spreadsheet

Уведомления о работе скрипта по email

После выполнения скрипта результаты его работы высылаются на email, указанный в конфигурационном файле. В письме содержится сводная статистика по обработанным площадкам и ссылка на документ с полным отчетом.

Пошаговое решение

1. Определение рабочего Google Spreadsheet и имя проекта.

var config = {
SPREADSHEET_URL:Link to the Google Spreadsheet',
PROJECT_NAME:'Name of the project',
}

2. Определение списка, в который будут заноситься «плохие», отфильтрованные площадки.

function getConfigData(spreadsheet) {
var excludeDomainSheet = spreadsheet.getSheetByName('exclude_domain'),
values =exclude DomainSheet.getSheetValues(1,1,excludeDomainSheet.getLastRow(),1);
config.exclude = [];
if (typeof values == "object") {
for (i=0; i < values.length; i++) {
config.exclude.push(values[i][0]);
}
}
Logger.log (config.exclude)

3. Определение списка для площадок, по которым не будет вноситься статистика.

var except DomainSheet = spreadsheet.getSheetByName('except_domain'),
values = except DomainSheet.getSheetValues(1,1,exceptDomainSheet.getLastRow(),1);
config.except = [];
if(typeof values == "object"){
for (i=0; i < values.length; i++) {
config.except.push(values[i][0]);
}
}
Logger.log (config.except)

4. Определение условий отбора площадок:

  • название списка,
  • контактный email,
  • отчетный период,
  • максимальная стоимость клика,
  • максимальная стоимость конверсии,
  • минимальное количество показов,
  • максимальный CTR.

var configSheet = spreadsheet.getSheetByName('config');
config.email = configSheet.getRange(1,2,1,1).getValues();
config.timeperiod = configSheet.getRange(2,2,1,1).getValue();
config.listCost = configSheet.getRange(3,2,1,1).getValue();
config.list2ConversionCost = configSheet.getRange(4,2,1,1).getValue();
config.list3Impressions = configSheet.getRange(5,2,1,1).getValue();
config.list3Ctr = configSheet.getRange(6,2,1,1).getValue();
config.list4Impressions = configSheet.getRange(7,2,1,1).getValue();
config.list4Ctr = configSheet.getRange(8,2,1,1).getValue()

5. Обновление названия документа с учетом даты запуска скрипта.

function main() {
var spreadsheet = SpreadsheetApp.openByUrl(config.SPREADSHEET_URL);
var curDate = Utilities.formatDate(new Date(), "GMT+3", "yyyy-MMMM-dd");
getConfigData(spreadsheet);
spreadsheet.setName("GDN Report " + config.PROJECT_NAME + " " + curDate)

6. Генерация отчета.

var body = "

Google Display Network – Report on underperforming placements

";
body += "

Placements that spent more than " + config.listCost + " USD and did not bring conversions:

" ;
body += "
    ";
    var list = runHightCostAndNoConvertingReport();
    varrows = [];
    for (i=0; i < list.length; i++) {
    body += "
  • " + list[i].placement + ' - ' + list[i].cost + ' USD ' + "
  • ";
    }
    addPlacementList('list1',list,spreadsheet);
    body += "
";
body += "

Placements with the conversion cost more than " + config.list2ConversionCost + " USD:

;
body += "
    ";
    var list2 = runHighCostOfConversionsReport();
    for (i=0; i < list2.length; i++) {
    body += "
  • " + list2[i].placement + ' - ' + list2[i].cost + ' USD ' + ' - The cost of conversion - ' + list2[i].costperconversion + ' USD ' + "
  • ";
    }
    addPlacementList('list2',list2,spreadsheet);
    body += "
";
body += "

Placements with more than " + config.list3Impressions + " impressions and CTR less than " + config.list3Ctr + "%:

" ;
body += "
    ";
    var list3 = runBadCtrNoConversionsReport();
    body += "
  • The number of exceptions - " + list3.length + "
  • ";
    addPlacementList('list3',list3,spreadsheet);
    body += "
";
body += "

Placements with more than " + config.list4Impressions + " impressions and CTR more than " + config.list4Ctr + "%:

" ;
body += "
    ";
    var list4 = runHighCtrReport();
    body += "
  • The number of exceptions - " + list4.length + "
  • ";
    addPlacementList('list4',list4,spreadsheet);
    body += "
";
body += "

The placements, which domain name contains the unwanted word:

" ;
body += "
    ";
    var list5 = gamePlacements();
    body += "
  • The number of exceptions - " + list5.length + "
  • ";
    addPlacementList('list5',list5,spreadsheet);
    body += "
";
body += "Link to the report Google Spreadsheet";

7. Отправка email с результатами.

if(config.email.length){
MailApp.sendEmail(config.email,'Display Network Alerts - ' + config.PROJECT_NAME + " - " + curDate, body, {htmlBody: body});
}

8. Использование функций для добавления площадок в исключения.

function addPlacementList(nameList,list,spreadsheet) {
var rows = [],
sheet,
range,
listSharedExcludedPlacementIterator;
sheet = spreadsheet.getSheetByName(nameList);
sheet.clear();
range = sheet.getRange(1, 1, 1, 7).setValues([['Exclusion URL','Impressions','Clicks','CTR','Cost','Conversions','Cost Per Conversion']]);
range.setBackground("yellow");
listSharedExcludedPlacementIterator = AdWordsApp.excludedPlacementLists()
.withCondition("Name CONTAINS '" + nameList + "'").get();
while (listSharedExcludedPlacementIterator.hasNext()) {
listSharedExcludedPlacement = listSharedExcludedPlacementIterator.next();
}
for (i=0; i < list.length; i++) {
listSharedExcludedPlacement.addExcludedPlacement(list[i].placement);
rows.push([list[i].placement, list[i].impressions, list[i].clicks, list[i].clicks / list[i].impressions * 100 + "%", list[i].cost, list[i].conversions, list[i].costperconversion])
}
if(rows.length)
sheet.getRange(2, 1, rows.length, 7).setValues(rows).sort({column: 2, ascending: false});
}
function runHightCostAndNoConvertingReport() {
list = [];
var periodString = '';
if(config.timeperiod) {
periodString = 'DURING ' + config.timeperiod;
Logger.log(periodString);
} else {
Logger.log('DURING ALL TIME');
}

9. Определение площадок, которые потратили более X USD и не принесли конверсий.

var report = AdWordsApp.report(
'SELECT Domain, Clicks, Impressions, CostPerConversion, Conversions, Cost ' +
'FROM AUTOMATIC_PLACEMENTS_PERFORMANCE_REPORT ' +
'WHERE Cost > ' + config.listCost * 1000000 + " " +
'AND Conversions < 1 ' +
periodString);
var rows = report.rows();
while (rows.hasNext()) {
var row = rows.next();
var anonymous = row['Domain'].match(new RegExp(config.except.join('|').replace(/\./g,'\\.'),'g'));
if (anonymous == null) {
var placementDetail = new placementObject(row['Domain'], row['Clicks'], row['Impressions'], row['CostPerConversion'],row['Conversions'], row['Cost']);
list.push(placementDetail);
}
}
return list;
}
function runHighCostOfConversionsReport() {
list = [];
var periodString = '';
if(config.timeperiod) {
periodString = 'DURING ' + config.timeperiod;
Logger.log(periodString);
} else {
Logger.log('DURING ALL TIME');
}

10. Определение площадок с конверсиями, которые стоят более X USD.

var report = AdWordsApp.report(
'SELECT Domain, Clicks, Impressions, CostPerConversion, Conversions, Cost ' +
'FROM AUTOMATIC_PLACEMENTS_PERFORMANCE_REPORT ' +
'WHERE CostPerConversion > ' + config.list2ConversionCost * 1000000 + " " +
'AND Conversions > 1 ' +
periodString);
var rows = report.rows();
while (rows.hasNext()) {
var row = rows.next();
var anonymous = row['Domain'].match(new RegExp(config.except.join('|').replace(/\./g,'\\.'),'g'));
if (anonymous == null) {
var placementDetail = new placementObject(row['Domain'], row['Clicks'], row['Impressions'], row['CostPerConversion'], row['Conversions'], row['Cost']);
list.push(placementDetail);
}
}
return list;
}
function runBadCtrNoConversionsReport() {
list = [];
var periodString = '';
if(config.timeperiod) {
periodString = 'DURING ' + config.timeperiod;
Logger.log(periodString);
} else {
Logger.log('DURING ALL TIME');
}

11. Определение площадок без конверсий с более чем X показами CTR менее Y %.

var report = AdWordsApp.report(
'SELECT Domain, Clicks, Impressions, CostPerConversion, Conversions, Cost ' +
'FROM AUTOMATIC_PLACEMENTS_PERFORMANCE_REPORT ' +
'WHERE Impressions > ' + config.list3Impressions + " " +
'AND Ctr < ' + config.list3Ctr * 0.01 + " " +
'AND Conversions < 1 ' +
periodString);
var rows = report.rows();
while (rows.hasNext()) {
var row = rows.next();
var anonymous = row['Domain'].match(new RegExp(config.except.join('|').replace(/\./g,'\\.'),'g'));
if (anonymous == null) {
var placementDetail = new placementObject(row['Domain'], row['Clicks'], row['Impressions'], row['CostPerConversion'], row['Conversions'], row['Cost']);
list.push(placementDetail);
}
}
return list;
}
function runHighCtrReport() {
list = [];
var periodString = '';
if(config.timeperiod) {
periodString = 'DURING ' + config.timeperiod;
Logger.log(periodString);
} else {
Logger.log('DURING ALL TIME');
}

12. Определение площадок без конверсий с более чем X показами и CTR большим, чем Y %.

var report = AdWordsApp.report(
'SELECT Domain, Clicks, Impressions, CostPerConversion, Conversions, Cost ' +
'FROM AUTOMATIC_PLACEMENTS_PERFORMANCE_REPORT ' +
'WHERE Impressions > ' + config.list4Impressions + " " +
'AND Ctr > ' + config.list4Ctr * 0.01 + " " +
'AND Conversions < 1 ' +
periodString);
var rows = report.rows();
while (rows.hasNext()) {
var row = rows.next();
var anonymous = row['Domain'].match(new RegExp(config.except.join('|').replace(/\./g,'\\.'),'g'));
if (anonymous == null) {
var placementDetail = new placementObject(row['Domain'], row['Clicks'],row['Impressions'], row['CostPerConversion'], row['Conversions'], row['Cost']);
list.push(placementDetail);
}
}
return list;
}
function gamePlacements() {
list = [];
var periodString = '';
if(config.timeperiod) {
periodString = 'DURING ' + config.timeperiod;
Logger.log(periodString);
} else {
Logger.log('DURING ALL TIME');
}

13. Добавление в исключения площадок без конверсий, в домене которых содержатся нежелательные слова.

var report = AdWordsApp.report(
'SELECT Domain, Clicks, Impressions, CostPerConversion, Conversions, Cost ' +
'FROM AUTOMATIC_PLACEMENTS_PERFORMANCE_REPORT ' +
'WHERE Conversions < 1 ' +
periodString);
var rows = report.rows();
while (rows.hasNext()) {
var row = rows.next();
var anonymous = row['Domain'].match(new RegExp(config.except.join('|').replace(/\./g,'\\.'),'g'));
if (anonymous == null) {
var placement = row['Domain'];
var clicks = row['Clicks'];
var impressions = row['Impressions'];
var costperconversion = row['CostPerConversion']
var conversions = row['Conversions'];
var cost = row['Cost'];
var placementDetail = new placementObject(placement, clicks, impressions, costperconversion, conversions, cost);
if (containsAny(placement.toString(), config.exclude)) {
var placementDetail = new placementObject(placement, clicks, impressions, costperconversion, conversions, cost);
list.push(placementDetail);
}
}
}
return list;
}
function containsAny(str, substrings) {
for (var i = 0; i != substrings.length; i++) {
var substring = substrings[i];
if (str.indexOf(substring) != - 1) {
return substring;
}
}
return null;
}
function placementObject(placement, clicks, impressions, costperconversion, conversions, cost) {
this.placement = placement;
this.clicks = clicks;
this.impressions = impressions;
this.costperconversion = costperconversion;
this.conversions = conversions;
this.cost = cost;
}

Результаты

Мы тестировали работу скрипта, используя следующие критерии отбора площадок:

результаты.png

Содержание письма:

Размещения, которые потратили более 300 USD и не принесли конверсий: 0
Размещения со стоимостью конверсии более чем 500 USD: 0
Размещения с более чем 100 показами и CTR, менее 0.05%: 3
Размещения с более чем 50 показами и CTR более 8%: 7
Размещения, содержащие в домене нежелательные слова: 382

Заключительные комментарии

При использовании нашего решения нужно помнить о следующих моментах:

  • «Отсеивающие» параметры можно и нужно прописывать с учетом особенностей вашего проекта.
  • Вы можете настроить автоматический запуск скрипта, например, еженедельно.
  • Если ваш аккаунт достаточно старый, мы рекомендуем проверить площадки за весь период его работы. Чтобы сделать это, просто оставьте поле с отчетным периодом пустым.
Читайте нас в Telegram - digital_bar

Есть о чем рассказать? Тогда присылайте свои материалы Даше Калинской


Новые 
Новые
Лучшие
Старые
Сообщество
Подписаться 
Подписаться на дискуссию:
E-mail:
ОК
Вы подписаны на комментарии
Ошибка. Пожалуйста, попробуйте ещё раз.
Отправить отзыв
  • Феликс Неботов
    1
    комментарий
    0
    читателей
    Феликс Неботов
    6 месяцев назад
    Вадим, здравствуйте.
    Чем отличается от этого скрипта?
    gist.github.com/derekmartinla/06e51b8a4298b8bbb8ff
    -
    0
    +
    Ответить
  • Гость
    1
    комментарий
    0
    читателей
    Гость
    6 месяцев назад
    Вадим, спасибо за отличный скрипт!
    Скажите, пожалуйста, а можно привязать выполнение скрипта к определенной кампании?
    -
    0
    +
    Ответить
  • Гость
    больше года назад
    Спасибо за полезную информацию. Можете ли поделится шаблоном файла настроек и содержимым скрипта, сложенным в один файл?
    -
    2
    +
    Ответить
    • Vadim Chernik
      1
      комментарий
      0
      читателей
      Vadim Chernik
      Гость
      6 месяцев назад
      Добрый день,

      Ссылка на шаблон таблицы с настройками: goo.gl/oOKdER
      Ссылка на весь скрипт: goo.gl/aIA0FL
      -
      1
      +
      Ответить
  • Гость
    больше года назад
    ого
    -
    1
    +
    Ответить
ПОПУЛЯРНЫЕ ОБСУЖДЕНИЯ НА SEONEWS
Кейс: как продвинуть сайт производителя мебели на заказ в Москве
Евгений
1
комментарий
0
читателей
Полный профиль
Евгений - Мне интересен бюджет данного проекта, можете примерно назвать цифры?
Рейтинг «Известность бренда SEO-компаний 2017»: народное голосование
Гость
1
комментарий
0
читателей
Полный профиль
Гость - 1) Ingate 2) Ашманов 3) Кокос 4) Russian Promo 5) Netpeak
«Баден-Баден»: как выйти из-под фильтра
Александр Кравцов
1
комментарий
0
читателей
Полный профиль
Александр Кравцов - Всем привет Вот ещё пациент www.gdebar.ru Под фильтром с 20 декабря, прошёл месяц, сегодня обновилось, что можете нажать сново проверить сайт и ждать 59 дней.Может кто сталкивался и сможет как то подсказать? Аудитом например или ещё как то проверить, что стоит подправить,скайп мой icejhell. Готов так же к совместному общению по решению проблемы. Всем успехов )
Второе дыхание ссылочного продвижения
Автопилот
15
комментариев
0
читателей
Полный профиль
Автопилот - Еще лучше, когда продвижение осуществляется комплексно :)
Западные специалисты выяснили, как повысить позиции ресурса в выдаче Google
Максим Мирошник
2
комментария
0
читателей
Полный профиль
Максим Мирошник -
Кейс: продвигаем бизнес по продаже пластиковых окон в Москве
Иван Стороженко
14
комментариев
0
читателей
Полный профиль
Иван Стороженко - 1. По началу вообще не использовали, сейчас уже много каналов используется. 2. Все может быть, в принципе сайты должны быть удобны для пользователя, для этого и нужна схожесть между собой. Честно говоря старались брать все самое интересное у конкурентов + подкреплять своими идеями.
«Прямая линия» с Александром Алаевым («АлаичЪ и Ко»): отвечаем на вопросы
Александр Алаев
13
комментариев
0
читателей
Полный профиль
Александр Алаев - Роман. Тут ответ очень простой. Каждый запрос можно четко разделить на коммерческий или некоммерческий. "Купить слона" и его длинные хвосты - коммерческий. "Как выбрать слона" и подобные - информационные. Вот под коммерческие ключи должны быть страницы услуг или каталога товаров. А под информационку - блог. Очень важно не путать их, тем более несоответствующая коммерческим факторам страниц просто не продвинется, то есть по запросу с "купить" блог никогда не будет показываться в выдаче, так же как и страница услуги/товаров не покажется по "как выбрать". Понятно примерно?
Контекст под SEO. Как поисковая реклама помогает позициям в органической выдаче
Кирилл Щербаков
1
комментарий
0
читателей
Полный профиль
Кирилл Щербаков - чет я не понял, за 3 года ничего с сайтами не делалось что ли? Типо он в статике висел и лился контекст?
Сердитый маркетолог: как вы сами хороните свой сайт, или 16 принципов, которые нужно усвоить заказчикам SEO
Dmitry Maslennikov
1
комментарий
0
читателей
Полный профиль
Dmitry Maslennikov - Особенно последний пункт в тему! Как клиент могу сказать что каждый потенциальный подрядчик по SEO пытался "утопить" предыдущего сеошника комментариями типа "что они вообще сделали" и "чем занимались год, у вас не сделаны элементарные вещи". Уровень сео-специлистов в регионах такой, что для клиентов я бы дал только один совет - не верьте в SEO - бесплатный сыр только в мышеловке.
«Прямая линия» с Артуром Латыповым: отвечаем на вопросы
God Koss
1
комментарий
0
читателей
Полный профиль
God Koss - Добрый день! Есть сайты одной компании продвигающиеся в разных странах. .ru .com .net. На российском сайте два языка ru и en, на остальных до 10 языков. Недавно сайт ru по основному брендовому запросу выпал из выдачи Яндекс но после апа вернулся на вторую позицию. На вопрос аффилирования в тех поддержку, получит ответ, что всё в порядке и сайт com не учавствует в выдаче. Но он есть и занимает 1 место. Как быть в данной ситуации? Так же, после возврата в топ 10 по этому запросу зашла еще одна внутренняя страница. Могло ли это случиться из-за каннибализации запроса? Немного изменил description на внутренней, исключил вхождения брендового запроса. Жду апа. Хотел бы услышать ваше мнение. Заранее благодарю!
ТОП КОММЕНТАТОРОВ
Комментариев
910
Комментариев
834
Комментариев
554
Комментариев
540
Комментариев
483
Комментариев
373
Комментариев
317
Комментариев
262
Комментариев
232
Комментариев
171
Комментариев
156
Комментариев
137
Комментариев
121
Комментариев
97
Комментариев
97
Комментариев
95
Комментариев
84
Комментариев
80
Комментариев
67
Комментариев
60
Комментариев
59
Комментариев
55
Комментариев
55
Комментариев
54
Комментариев
52

Отправьте отзыв!
Отправьте отзыв!