搜尋查詢最佳化 - 單一帳戶

報表圖示

這個指令碼會比較搜尋字詞檢視報表中的搜尋字詞成效,以及您為產生正面和排除關鍵字 (完全比對) 關鍵字的清單。

運作方式

如要瞭解 Google Ads 指令碼中報表的運作方式,請參閱專屬的報表指南報表範例頁面

這項解決方案會執行搜尋查詢報表,找出點閱率不足時可能錯失的搜尋字詞,並新增為排除關鍵字,避免這些字詞觸發您的廣告。

指令碼也會尋找點閱率高和單次轉換費用低的關鍵字,然後將這些關鍵字新增為正面關鍵字。

設定

  • 使用下方的原始碼建立新指令碼。
  • 指令碼預覽時,很有可能在 30 秒預覽視窗中執行完畢。如果沒有,請嘗試將條件 DURING LAST_7_DAYS 變更為 DURING YESTERDAY
  • 指令碼完成預覽後,您會看到一份要新增為排除關鍵字 (有時是肯定) 關鍵字的清單。

原始碼

// Copyright 2015, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @name Search Query Report
 *
 * @overview The Search Query Report script uses the Search Query Performance
 *     Report to find undesired search terms and add them as negative (or
 *     positive) exact keywords. See
 *     https://developers.google.com/google-ads/scripts/docs/solutions/search-query
 *     for more details.
 *
 * @author Google Ads Scripts Team [adwords-scripts@googlegroups.com]
 *
 * @version 2.0
 *
 * @changelog
 * - version 2.0
 *   - Updated to use new Google Ads scripts features.
 * - version 1.0.1
 *   - Upgrade to API version v201609.
 * - version 1.0
 *   - Released initial version.
 */

// Minimum number of impressions to consider "enough data"
const IMPRESSIONS_THRESHOLD = 100;
// Cost-per-click (in account currency) we consider an expensive keyword.
const AVERAGE_CPC_THRESHOLD = 1; // $1
// Threshold we use to decide if a keyword is a good performer or bad.
const CTR_THRESHOLD = 0.5; // 0.5%
// If ctr is above threshold AND our conversion cost isn’t too high,
// it’ll become a positive keyword.
const COST_PER_CONVERSION_THRESHOLD = 10; // $10

/**
 * Configuration to be used for running reports.
 */
const REPORTING_OPTIONS = {
  // Comment out the following line to default to the latest reporting version.
  apiVersion: 'v11'
};

function main() {
  const report = AdsApp.report(
      `SELECT search_term_view.search_term, ` +
      `metrics.clicks, ` +
      `metrics.cost_micros, ` +
      `metrics.ctr, ` +
      `metrics.conversions_from_interactions_rate, ` +
      `metrics.cost_per_conversion, ` +
      `metrics.conversions, ` +
      `campaign.id, ` +
      `ad_group.id ` +
      `FROM search_term_view ` +
      `WHERE metrics.conversions > -1 ` +
      `AND metrics.impressions > ${IMPRESSIONS_THRESHOLD} ` +
      `AND metrics.average_cpc > ${AVERAGE_CPC_THRESHOLD} ` +
      `AND segments.date DURING LAST_7_DAYS`, REPORTING_OPTIONS);

  const rows = report.rows();
  const negativeKeywords = {};
  const positiveKeywords = {};
  const allAdGroupIds = {};
  // Iterate through search query and decide whether to
  // add them as positive or negative keywords (or ignore).
  for (const row of rows) {
    if (parseFloat(row['metrics.ctr*100%']) < CTR_THRESHOLD) {
      addToMultiMap(negativeKeywords, row['ad_group.id'],
                    row['search_term_view.search_term']);
      allAdGroupIds[row['ad_group.id']] = true;
    } else if (parseFloat(row['metrics.cost_per_conversion']) <
        COST_PER_CONVERSION_THRESHOLD ||
        !(parseFloat(row['metrics.cost_per_conversion']))) {
        addToMultiMap(positiveKeywords, row['ad_group.id'],
                    row['search_term_view.search_term']);
        allAdGroupIds[row['ad_group.id']] = true;
    }
  }

  // Copy all the adGroupIds from the object into an array.
  const adGroupIdList = [];
  for (const adGroupId in allAdGroupIds) {
    adGroupIdList.push(adGroupId);
  }

  // Add the keywords as negative or positive to the applicable ad groups.
  const adGroups = AdsApp.adGroups().withIds(adGroupIdList).get();
  for (const adGroup of adGroups) {
    if (negativeKeywords[adGroup.getId()]) {
      for (const negativeKeyword of negativeKeywords[adGroup.getId()]) {
        adGroup.createNegativeKeyword(`[${negativeKeyword}]`);
      }
    }
    else if (positiveKeywords[adGroup.getId()]) {
      for (const positiveKeyword of positiveKeywords[adGroup.getId()]) {
        adGroup.newKeywordBuilder()
            .withText(`[${positiveKeyword}]`)
            .build();
      }
    }
  }
}

function addToMultiMap(map, key, value) {
  if (!map[key]) {
    map[key] = [];
  }
  map[key].push(value);
}