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. Пример Google Spreadsheet со словами, по которым отсеиваются домены

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

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

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

Рис. 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 = "<h2>Google Display Network – Report on underperforming placements</h2>";

body += "<h3>Placements that spent more than " + config.listCost + " USD and did not bring conversions:</h3> " ;

body += "<ul>";

var list = runHightCostAndNoConvertingReport();

varrows = [];

for (i=0; i < list.length; i++) {

body += "<li>" + list[i].placement + ‘ – ‘ + list[i].cost + ‘ USD ‘ + "</li>";

}

addPlacementList(‘list1’,list,spreadsheet);

body += "</ul>";

body += "<h3>Placements with the conversion cost more than " + config.list2ConversionCost + " USD:</h3> ;

body += "<ul>";

var list2 = runHighCostOfConversionsReport();

for (i=0; i < list2.length; i++) {

body += "<li>" + list2[i].placement + ‘ – ‘ + list2[i].cost + ‘ USD ‘ + ‘ – The cost of conversion – ‘ + list2[i].costperconversion + ‘ USD ‘ + "</li>";

}

addPlacementList(‘list2’,list2,spreadsheet);

body += "</ul>";

body += "<h3>Placements with more than " + config.list3Impressions + " impressions and CTR less than " + config.list3Ctr + "%:</h3> " ;

body += "<ul>";

var list3 = runBadCtrNoConversionsReport();

body += "<li>The number of exceptions – " + list3.length + "</li>";

addPlacementList(‘list3’,list3,spreadsheet);

body += "</ul>";

body += "<h3>Placements with more than " + config.list4Impressions + " impressions and CTR more than " + config.list4Ctr + "%:</h3> " ;

body += "<ul>";

var list4 = runHighCtrReport();

body += "<li>The number of exceptions – " + list4.length + "</li>";

addPlacementList(‘list4’,list4,spreadsheet);

body += "</ul>";

body += "<h3>The placements, which domain name contains the unwanted word:</h3> " ;

body += "<ul>";

var list5 = gamePlacements();

body += "<li> The number of exceptions – " + list5.length + "</li>";

addPlacementList(‘list5’,list5,spreadsheet);

body += "</ul>";

body += "<a href=’"+spreadsheet.getUrl()+"’>Link to the report Google Spreadsheet</a>";

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;

}

Результаты

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

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

Размещения, которые потратили более 300 USD и не принесли конверсий: 0

Размещения со стоимостью конверсии более чем 500 USD: 0

Размещения с более чем 100 показами и CTR, менее 0.05%: 3

Размещения с более чем 50 показами и CTR более 8%: 7

Размещения, содержащие в домене нежелательные слова: 382

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

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

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

Источник: seonews.ru


Добавить комментарий

Войти с помощью: 

Ваш e-mail не будет опубликован. Обязательные поля помечены *