- PVSM.RU - https://www.pvsm.ru -
За последние полгода нам удалось победить «скликивание» нашей контекстной рекламы с бюджетом в 1 миллион рублей в месяц.
Ключом победы над фродом стал поминутный мониторинг трафика с уведомлениями об аномальных изменениях и отключением проблемных объявлений по API, и ряд отчётов, которые отражают ситуацию в реальном времени.
Рисунок 1. Диаграмма количества посетителей по ключевым словам по декаминутам
Одним из первых признаков «скликивания» рекламы будет увеличение процента возвращаемых средств за фрод в Директе и AdWords.
«В Яндекс Директ расходы на фрод автоматически возвращаются на баланс рекламной кампании. Количество кликов, отсеянных системой защиты от фрода, отображается в отчетах «статистика по дням» «общая статистика» в строке «недействительные клики за весь выбранный период.»
– справка Я. Директа «недействительных кликах» [1].
В AdWords отображение уровня «недействительных кликов» можно включить на вкладке «столбцы»:
Рисунок 2. Настроенные столбцы с уровнем «недействительных кликов» в AdWords
В нашем случае, при среднем уровне «недействительных кликов [1]» в Директе ≈ 10%, Яндексе вдруг стал возвращать 40% рекламного бюджета, а через месяц и вовсе 54%.
Следующий признак фрода – это необоснованный рост количества переходов и сильные изменения поведенческих показателей по ряду групп объявлений.
Мы заметили, что по ряду ключевых слов, по которым никогда не было больше 200 посетителей в день, вдруг появились всплески до 3 000 посетителей. По факту, бюджет, в дни подобных активностей, мог уйти на одну рекламную кампанию, если её вовремя не останавливали.
Рисунок 3. Необоснованный рост трафика по определенной группе объявлений в Директ
Достаточно прочесть обсуждение уровня фрода в контекстной рекламе [2] в официальном Клубе Директа, чтобы убедиться: многие рекламодатели теряют из-за фрода деньги.
Google официально признаёт ошибки своей системы защиты и предоставляет рекламодателям «Refund Claims» (возврат израсходованного бюджета). По статистике сервиса ClickSease, Google Ads в среднем возвращает 12% рекламного бюджета.
В нашем случае, Google AdWords сначала признал 18% нашего трафика «недействительными [4]» и вернул за них деньги, а когда мы отправили жалобу «refund claims», Google возместил ещё 13% бюджета.
Яндекс же не признаёт уязвимость собственных фильтров защиты и на жалобы об очевидных случаях фрода, отправляет шаблонный ответ, что проблема заключается в рекламодателе и его сайте.
В нашем случае, процент «недействительных кликов» в отчёте Я. Директа никогда не поднимался выше заветных 50% ни по одной из рекламных кампаний, даже в дни самых яростных всплесков, когда 80% бюджета «сливалось» на обычно мало популярную группу объявлений без звонков и заявок.
Рисунок 4. Уровень «недействительных кликов» в одной из кампаний в Директ
Мошеннический трафик направлялся по четырем направлениям бизнеса в двух городах. При подключении новых рекламных кампаний или запуске давно остановленных, в течение нескольких часов «скликивание» перераспределялось и на них.
Click Fraud не привязывался ко времени, и перераспределение бюджета, например на ночь, не давало никакого эффекта: свой объем левого трафика мы всё равно получали. «Скликивание» происходило одинаково активно и в РСЯ, и на поиске Яндекса, и в КМС Google.
На сайте боты симулировали поведение пользователя, переходили по разделам сайта, выделяли текст, естественно скролили и перемещали курсор.
У всех сервисов защиты от кликфрода есть всего один инструмент прямой борьбы – это блокировка подозрительных IP адресов или площадок размещений в кампаниях Я.Директ и AdWords.
В случае, если против вас используются динамические IP, любой сервис борьбы с клик фродом всегда будет отставать на один шаг от мошенников в блокировке их по IP: бот уже совершит несколько кликов по вашей рекламе к тому моменту, когда сервис внесет этот IP в черный список и остановит по нему показ рекламы. К тому же, после того, как мошеннический софт не сможет увидеть вашу рекламу, он просто поменяет IP адрес, Hardware-ID и продолжит свои действия.
При атаке на рекламу в КМС или РСЯ, обычно используются различные места размещения, и системы автоматической защиты не могут обнаружить подозрительных площадок для блокировки.
Вернемся к блокировке по IP – здесь мы подходим к самому интересному – если в AdWords допускается блокировать до 500 IP адресов, то в Яндекс Директ можно блокировать всего лишь 25 уникальных IP адресов на одну рекламную кампанию! Столь маленький черный список IP адресов уже не актуален, так как сейчас можно спокойно закупить 500 IPv4 адресов за 10 тысяч рублей и обойти это ограничение.
Защититься от «скликивания», выполняемого на высоком уровне, можно всего двумя способами:
Если научиться не показывать рекламу клик ботам или мошенническим пользователям – то и навредить они не смогут.
Всегда можно отследить схожие модели поведения и паттерны, например, что фрод обычно идет по Windows 7 с 5:00 до 9:00 в Москве, и выставить корректировку ставок -100% для подобной аудитории во всех атакуемых рекламных кампаниях. Функционал корректировок ставок в AdWords [5] достаточно обширен, чего не скажешь о корректировках в Yandex Direct [6].
Для того, чтобы иметь представление о том, как именно нас атакуют, и вручную отследить закономерности в мошенническом трафике, мы подключили российский сервис защиты от фрода ClickFrog [7]. Продукт это давно всем известный, популярный в среде CPA и так далее.
ClickFrog быстро доказал полную недееспособность:
Затем мы установили код американского сервиса ClickSease [8], нацеленного на AdWords, и пока ещё не работающего с Директом. У сервиса, кстати, есть, в отличие от ClickFrog, бесплатный тестовый период на 2 недели.
ClickSease оказался полезнее: он начал вылавливать по 300-400 уникальных мошеннических IP в день. По каждому заблокированному IP сервис отдает статистику:
Из отчета ClickSease нам удалось выявить закономерности во фроде:
Однако даже таких очевидных паттернов оказалось мало для снижения вреда от фрода, да и отключать рекламу на мобильных не хотелось. Сервисы обычно способны только дать идеи по выявлению схожих паттернов во фроде, а дальше необходимо обнаружить фрод в Метрике (в случае атаки на Директ) и выделить его в отдельных сегмент Яндекс Аудиторий для последующего анализа и блокировки.
Рисунок 5. Пример анализа трафика по возрастным группам в Метрике для поиска паттернов фрода
Срезы трафика, которые помогут определить паттерны фрода:
В случае AdWords механика противодействия ясна:
В Яндекс Директ механика борьбы сложнее и разделяется на два варианта:
а) вам удалось найти очевидный паттерн фрода, относящийся к полу, возрасту или мобильности:
б) очевидных паттернов не обнаружено:
Фрод всегда порождает очевидные очаги и пики, будь то заумный софт с имитацией поведения настоящего пользователя или группа фрилансеров, выполняющих техническое задание.
Рисунок 6. Диаграмма количества посетителей по ключевым словам по декаминутам
Фрод происходит неравномерно по нескольким причинам:
Если научится оперативно находить и устранять очаги, то можно заметно снизить вред от фрода. В нашем случае, очевидным признаком стало аномальное увеличение количества переходов по контекстной рекламе в конкретных 10 минутах или одной минуте по некоторым ключевым словам.
Для визуализации лучше всего подойдёт Google Data Studio [11], поскольку корректно собирать данные, разбитые по времени на 1 и 10 минут, способен только Analytics, а Метрика, при построении отчетов по декаминутам, отдаёт некорректные показатели.
Шаг 1. Открываем редактирование полей
Шаг 2. Создаем копии следующих полей: Год, Месяц года, День месяца, Час, Минута, и называем их, например, Год (число), Месяц года (число) и так далее. Также в скопированных полях необходимо изменить Тип с формата времени и даты на „число“ как показано на рисунке.
Шаг 2. Изменяем тип скопированного поля с «даты» на «число»
Шаг 3. Создаем новое поле, в котором прописываем следующую формулу: Год (число)*10000000+Месяц года (число)*100000+День месяца (число)*1000+Час (число)*10+FLOOR(Минута (число)/10)
Шаг 3. Создаём вычисляемое поле «Время по 10 минут»
Шаг 4. Сохраняем созданное поле, затем возвращаемся к списку всех полей и находим наше новое поле «Время по 10 минут (декаминут)». Необходимо изменить его тип с «Число» на «Дата и время» как показано на рисунке, а затем обратно присвоить этому полю тип «Число».
Шаг 4. Создаём вычисляемое поле „Время по 10 минут“
Шаг 5. Создаем «Комбинированную диаграмму» и ставим как параметр наше новое поле «Время по 10 минут», как показано на рисунке. Готово.
Шаг 5. Создаём «комбинированную диаграмму»
Чтобы не следить за всеми случаями фрода вручную, я сделал отчёт в Google Таблицах, который обновляет данные каждую минуту и уведомляет о начале фрода.
Google Таблицы поддерживают Core Reporting API [12], обращаться к которому можно через «Редактор скриптов» в Таблицах.
Шаг 1. Заходим в редактор скриптов для обращения к Analytics
Рисунок 7. Редактор скриптов для обращения к Analytics Core Reporting API через Гугл Таблицы
Шаг 2. Прописываем API запрос к Analytics, чтобы получать данные о нужных показателях (например, о количестве пользователей, перешедших по платной рекламе, в каждую минуту суток, как в нашем случае).
function runDemo() {
try {
var firstProfile = getFirstProfile();
var results = getReportDataForProfile(firstProfile);
outputToSpreadsheet(results);
} catch(error) {
Browser.msgBox(error.message);
}
}
function getFirstProfile() {
var accounts = Analytics.Management.Accounts.list();
if (accounts.getItems()) {
var firstAccountId = accounts.getItems()[0].getId();
var webProperties = Analytics.Management.Webproperties.list(firstAccountId);
if (webProperties.getItems()) {
var firstWebPropertyId = webProperties.getItems()[0].getId();
var profiles = Analytics.Management.Profiles.list(firstAccountId, firstWebPropertyId);
if (profiles.getItems()) {
var firstProfile = profiles.getItems()[0];
return firstProfile;
} else {
throw new Error('No views (profiles) found.');
}
} else {
throw new Error('No webproperties found.');
}
} else {
throw new Error('No accounts found.');
}
}
function getReportDataForProfile(firstProfile) {
var profileId = firstProfile.getId();
var tableId = 'ga:' + profileId;
var startDate = "today"; //например getLastNdays(14) равняется 2 weeks (a fortnight) ago.
var endDate = "today"; //getLastNdays(0) равняется Today.
var optArgs = {
'dimensions': 'ga:date,ga:hour,ga:minute,ga:sourceMedium', // Comma separated list of dimensions.
'sort': 'ga:date,ga:hour,ga:minute', // Sort by sessions descending, then keyword.
//'segment': 'dynamic::ga:isMobile==Yes', // Process only mobile traffic.
'filters': 'ga:sourceMedium==yandex / cpc',
'start-index': '1',
'max-results': '10000' // Display the first 250 results.
};
// Make a request to the API.
var results = Analytics.Data.Ga.get(
tableId, // Table id (format ga:xxxxxx).
startDate, // Start-date (format yyyy-MM-dd).
endDate, // End-date (format yyyy-MM-dd).
'ga:users', // Comma seperated list of metrics.
optArgs);
if (results.getRows()) {
return results;
} else {
throw new Error('No views (profiles) found');
}
}
function getLastNdays(nDaysAgo) {
var today = new Date();
var before = new Date();
before.setDate(today.getDate() - nDaysAgo);
return Utilities.formatDate(before, 'GMT', 'yyyy-MM-dd');
}
function outputToSpreadsheet(results) {
var sheets = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sheets.getSheetByName("coeff1");
var range = sheet.getRange('A:E');
range.clear();
// Print the headers.
var headerNames = [];
for (var i = 0, header; header = results.getColumnHeaders()[i]; ++i) {
headerNames.push(header.getName());
}
sheet.getRange(1, 1, 1, headerNames.length)
.setValues([headerNames]);
// Print the rows of data.
sheet.getRange(2, 1, results.getRows().length, headerNames.length)
.setValues(results.getRows());
}
Шаг 3. Задаем триггер на обновление данных каждую минуту:
Рисунок 8. Запрашиваем свежие данные каждую минуту для оперативного реагирования на фрод
Шаг 4. Создаем сводную таблицу из листа, обновляемого нужными данными раз в минуту, и анализируем эти показатели для настройки триггеров для уведомлений на электронную почту или же отключения групп объявлений по API Я.Директа или AdWords.
Рисунок 9. Пример настройки формул для уведомлений об аномалиях
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("notification");
var range = sheet.getRange("D2:E4");
// The row and column here are relative to the range
// getCell(1,1) in this code returns the cell at B2, B2
var cell = range.getCell(1, 2);
Logger.log(cell.getValue());
if (cell.getValue() !== "no") {
MailApp.sendEmail("your_email@yandex.ru", "Fraud notification "+cell.getValue(), "Check me "+range.getCell(1, 1).getValue());
}
else {
}
var cell2 = range.getCell(2, 2);
Logger.log(cell2.getValue());
if (cell2.getValue() !== "no") {
MailApp.sendEmail("your_email@yandex.ru", "Fraud notification "+cell2.getValue(), "Check me "+range.getCell(2, 1).getValue());
}
else {
}
var cell3 = range.getCell(3, 2);
Logger.log(cell3.getValue());
if (cell3.getValue() !== "no") {
MailApp.sendEmail("your_email@yandex.ru", "Fraud notification "+cell3.getValue(), "Check me "+range.getCell(3, 1).getValue());
}
else {
}
}
Противодействие клик фроду можно подразделить на три группы:
а) Упреждающие действия:
б) Профилактические действия:
в) Действия «post factum»:
Рисунок 10. Способы защиты от click fraud
Полезные ссылки:
В нашем случае, конкурент ещё и начал клик фрод по 4 направлениям в двух городах, поэтому вычислить его не составило труда.
Чтобы было проще анализировать конкурентов, с которыми вы пересекаетесь, можно смотреть все включенные объявления конкурентов по каждому ключевому слову в интерефейсе Директа:
Рисунок 9. Все объявления конкурентов по ключевому слову
Кто также столкнулся со скликиванием контекстной рекламы – пишите в комментариях, постараемся помочь друг другу!
Автор: DanilNN
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/informatsionnaya-bezopasnost/292616
Ссылки в тексте:
[1] справка Я. Директа «недействительных кликах»: https://yandex.ru/support/direct/technologies-and-services/antifraud.html
[2] обсуждение уровня фрода в контекстной рекламе: https://yandex.ru/blog/direct/14427
[3] жалобу на «недействительные клики»: https://support.google.com/adwords/troubleshooter/2557048?rd=1
[4] недействительными: https://support.google.com/adwords/answer/2549113?ctx=tltp
[5] корректировок ставок в AdWords: https://support.google.com/google-ads/answer/2732132?hl=ru
[6] корректировках в Yandex Direct: https://yandex.ru/support/direct/impressions/bids-adjustment.html
[7] ClickFrog: https://clickfrog.ru/
[8] ClickSease: https://www.clickcease.com
[9] Яндекс.Аудиторий: https://audience.yandex.ru/
[10] look-alike Яндекса: https://yandex.ru/support/audience/segments/look-alike.html
[11] Google Data Studio: https://datastudio.google.com
[12] Core Reporting API: https://developers.google.com/analytics/devguides/reporting/core/v3/
[13] Библиотека: https://developers.google.com/analytics/devguides/reporting/core/v4/
[14] Query Explorer: https://ga-dev-tools.appspot.com/query-explorer/#report-start
[15] Пишем скрипты для автоматизации работы с приложениями Google: https://xakep.ru/2015/01/08/google-apps-script/
[16] Automate Google Sheets: https://zapier.com/learn/google-sheets/google-apps-script-tutorial/
[17] Analytics Intelligence: https://support.google.com/analytics/answer/7347597?hl=en
[18] Источник: https://habr.com/post/423335/?utm_campaign=423335
Нажмите здесь для печати.