Рекламная кампания в Google Ads на основе ключевых слов конкурентов

Как создать масштабную кампанию на основе ключевых слов конкурентов без ручного труда и собрать огромные объемы данных?

Для примера я возьму базу данных конкурентов, собранную по методу, описанному в другой моей статье — «Как шпионить за конкурентами в Google Ads«.

Преимуществами такого подхода будут:

  • Дело в том, что вы получите всех реальных конкурентов в поисковой рекламе, а не только тех, о которых сможете подумать\запомнить.
  • Тот факт, что у вас будут данные о степени пересечения ваших запросов с запросами конкурентов‘ позволит вам выбрать наиболее релевантные из них.

Итак, данные находятся в моем BigQuery. В таблицах нас интересуют эти поля:

Field nameTypeMode
domainSTRINGNULLABLE
keywordSTRINGNULLABLE

Этого достаточно для создания структуры кампании.

Вам необходимо включить службу BigQuery в расширенных API. Мы получим данные для скрипта, используя следующую функцию:

function get_competitors() {
    var project_name = '**********', // Project name
        dataset_name = '**********', // dataset name
        tables_mask = 'AU_IS_*';
    var queryRequest = BigQuery.newQueryRequest();
    queryRequest.query = 'SELECT COUNT(keyword) AS keys, domain ' +
        'FROM `' + project_name + '.' + dataset_name + '.AU_IS_*` ' +
        // enter your dates
        'WHERE SUBSTR(_TABLE_SUFFIX,-8) BETWEEN "20210121" AND "20210821" ' +
        'GROUP BY domain ' +
        'ORDER BY keys DESC ' +
        'LIMIT 500'; // top-how many competitors do we want to select?
    queryRequest.useLegacySql = false;
    var query = BigQuery.Jobs.query(queryRequest, project_name);
    var values = [];
    if (query.jobComplete) {
        for (var i = 0; i < query.rows.length; i++) {
            var row = query.rows[i];
            var domain = row.f[1].v;
            if (domain.indexOf('.') > -1) {
                values.push(domain);
            }
        }
    }
    return values;
}

Эта функция возвращает домены конкурентов в порядке убывания охвата поисковых запросов. Логично предположить, что чем больше конкурент освещает ваши запросы, тем более они релевантны для вас и тем интереснее для вас их запросы.

Если вы начинаете кампанию с нуля и у вас нет аналогичной истории данных, вы можете эмулировать ее, например, используя функцию сбора объявлений конкурентов в Key Collector или любой другой подобный сервис.

Далее переходим к созданию структуры кампании. Все, что вам нужно сделать заранее, это создать пустую кампанию, которую мы заполним группами, используя следующую функцию:

function buildGroups() {
    var campaignSelector = AdsApp
        .campaigns()
        .withCondition('Name CONTAINS_IGNORE_CASE "Competitors"'); // select this campaign
    var campaignIterator = campaignSelector.get();
    while (campaignIterator.hasNext()) {
        var campaign = campaignIterator.next();
        var competitors = get_competitors(); // get competitors' domains from BigQuery
        for (var i = 0; i < competitors.length; i++) {
            var adGroupSelector = campaign
                .adGroups()
                .withCondition('Name CONTAINS_IGNORE_CASE "' + competitors[i] + '"');
            var adGroupIterator = adGroupSelector.get();
            if (!adGroupIterator.hasNext()) {
                var adGroupBuilder = campaign.newAdGroupBuilder();
                var adGroupOperation = adGroupBuilder
                    .withName(competitors[i])
                    .withStatus("PAUSED")
                    .build();
                // create a ad group by the competitor's domain, if there was no such group in the campaign before
            }
        }
    }
}

Вы можете регулярно запускать эту функцию — она будет добавлять группы‘ если в базе данных появятся новые записи конкурентов.

Теперь самое интересное — вам нужно заполнить свои группы ключевыми словами ваших конкурентов.

Для этого я взял данные из сервиса SimilarWeb API. У них есть подходящий метод (я использую Desktop Non-Branded Keywords), плюс их данные показались мне подходящими как качественно, так и количественно.

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

Вот функция для получения ключевых слов по доменам с помощью программного обеспечения:

function get_keys(domain) {
    var apiKey = '1234567890qwertyuiop'; // API key
    var MILLIS_PER_DAY = 1000 * 60 * 60 * 24,
        now = new Date(),
        fromDate = new Date(now.getTime() - 365 * MILLIS_PER_DAY),
        toDate = new Date(now.getTime() - 31 * MILLIS_PER_DAY),
        nowDate = new Date(now.getTime()),
        timeZone = AdsApp.currentAccount().getTimeZone(),
        fromformatDate = Utilities.formatDate(fromDate, timeZone, 'yyyy-MM'),
        toformatDate = Utilities.formatDate(toDate, timeZone, 'yyyy-MM');
    var url = 'https://api.similarweb.com/v1/website/' + domain +
        '/traffic-sources/nonbranded-search?api_key=' + apiKey +
        '&start_date=' + fromformatDate +
        '&end_date=' + toformatDate +
        '&country=world&limit=10000&main_domain_only=false&format=json';
    // Logger.log(url);
    var options = {
        muteHttpExceptions: true,
        method: 'GET',
        contentType: 'application/json'
    };
    var response = UrlFetchApp.fetch(url, options);
    var json = JSON.parse(response);
    if (!!json.meta.status) {
        if (json.meta.status == 'Error') {
            return null
        }
        if (json.meta.status == 'Success') {
            var keysArr = [];
            for (var k = 0; k < json.search.length; k++) {
                var key = json.search[k].search_term;
                if (key.split(' ').length < 5) {
                    // I decided to take only phrases shorter than 5 words
                    keysArr.push(key);
                }
            }
            return keysArr;
        }
    }
}

На данном этапе я беру только исходный текст фразы, ради скорости работы скрипта. Можно было бы создать фразу и точные соответствия сразу, но тогда время добавления ключей в группу увеличилось бы втрое. Правильнее заполнить один вариант, и только потом создавать из него необходимые типы совпадений.

Итак, у нас есть функция получения ключей по доменам — давайте разделим их на группы.

Вот функция для заполнения групп:

function buildKeys() {
    var campaignSelector = AdsApp
        .campaigns()
        .withCondition('Name CONTAINS_IGNORE_CASE "Competitors"');
    var campaignIterator = campaignSelector.get();
    while (campaignIterator.hasNext()) {
        var campaign = campaignIterator.next();
        var adGroupSelector = campaign
            .adGroups()
            .withCondition('Status = PAUSED')
            .withCondition('Name DOES_NOT_CONTAIN "_"')
            .orderBy('Name ASC');
        // Take only ad groups that are still stopped and not processed
        // When running the script regularly, this is convenient
        // as soon as you start the ad group - the data stops updating
        var adGroupIterator = adGroupSelector.get();
        while (adGroupIterator.hasNext()) {
            var adGroup = adGroupIterator.next(),
                adGroupName = adGroup.getName();
            adGroup.setName('_' + adGroupName);
            // mark the group as processed
            var domain = adGroupName;
            Logger.log(domain);
            var keywordSelector = adGroup
                .keywords();
            var keywordIterator = keywordSelector.get();
            if (!keywordIterator.hasNext()) {
                var keys = get_keys(domain);
                // get phrases
                if ((!!keys) && (keys != null) && (keys.length > +0)) {
                    for (var n = 0; n < keys.length; n++) {
                        try {
                            var keywordOperation = adGroup.newKeywordBuilder()
                                .withText(keys[n])
                                .build();
                            // create phrase
                        } catch (e) {
                            Logger.log(e);
                        }
                    }
                }
            }
        }
    }
}

Здесь есть несколько особенностей:

  1. Скрипт помечает группу как обработанную, даже если получить ключевые слова для домена не удалось. Это необходимо для случаев, когда домен конкурента еще новый и шпионский сервис еще не собрал данные о нем.
  2. Для максимальной скорости ключи добавляются без каких-либо преобразований или проверки успешности операции добавления.

Я должен объяснить, почему я уже второй раз упоминаю скорость. Дело в том, что вы можете получить много ключевых слов для крупных конкурентов. Настолько, что добавление фраз только в одну группу не успеет отработать отведенные 30 минут.

С вышеуказанными настройками примерно за 3 дня автоматического запуска скрипта я получил кампанию из 500 групп и ~ 800 000 фраз.

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