AI로 자동화하는 Google Ads 부정 키워드 관리

AI로 자동화하는 Google Ads 부정 키워드 관리

FlowHunt는 AI로 Google Ads 부정 키워드 관리를 자동화하여, 기업이 비용을 절감하고, 광고비를 최적화하며, 캠페인 성과를 손쉽게 개선할 수 있도록 돕습니다.

불필요한 키워드 광고비 이해하기

불필요한 키워드 광고비는 광고가 실제 판매하는 상품과 맞지 않는 검색 결과에 노출될 때 발생합니다. 이런 경우 관련 없는 클릭에도 비용이 지출되고, 실제 구매로 이어지지 않아 예산이 빠르게 소진될 수 있습니다. 예를 들어, 고급 가죽 신발을 판매하는 회사가 “신발 구매”와 같이 광범위한 키워드를 타겟팅하면, 운동화나 샌들에 관심 있는 사람들의 클릭까지 유입될 수 있습니다. 이렇게 키워드 타겟팅이 미스매치되면 광고비가 낭비되고 ROI도 떨어집니다. 기업은 이 개념을 명확히 이해하고 예산을 적절한 키워드에 집중해야 불필요한 손실을 막을 수 있습니다.

부정 키워드의 역할

부정 키워드는 Google Ads 캠페인에서 필수적인 도구입니다. 광고주가 특정 검색어를 제외시켜, 오직 관련성 높은 검색에만 광고가 노출되도록 할 수 있습니다. 예를 들어, “저렴한”, “할인”과 같은 부정 키워드를 활용하면 고급 제품을 원하는 고객만 타깃팅할 수 있습니다. 부정 키워드 리스트를 세심하게 관리하면, 불필요한 클릭을 줄이고 광고비의 효율을 개선하여 캠페인 성과를 극대화할 수 있습니다.

AI를 활용한 키워드 관리

인공지능(AI)은 광고주가 Google Ads 캠페인을 관리하는 방식을 혁신하고 있습니다. FlowHunt와 같은 AI 도구는 키워드 그룹핑에 최적화되어, 연관된 키워드를 효과적으로 식별하고 조직화할 수 있도록 돕습니다. 이 자동화는 긍정/부정 키워드 모두를 손쉽게 찾을 수 있게 하며, 캠페인 관리에 필요한 수작업을 크게 줄여줍니다. AI 기반 키워드 관리는 실시간 성과 데이터에 따라 즉각적인 변경이 가능하여, 광고비가 항상 최고의 ROI로 운용되도록 보장합니다.

불필요한 키워드 광고비를 줄이는 전략

불필요한 키워드 광고비를 줄이기 위해, 기업은 다음과 같은 전략을 도입해야 합니다:

  • 키워드 리스트를 정기적으로 업데이트하여 시장 변화와 소비자 관심사를 반영하세요.
  • 강력한 부정 키워드 전략 구축: 지속적으로 제외할 키워드를 리서치하고 리스트를 최신 상태로 유지하세요.
  • 성과 데이터에 따라 캠페인을 모니터링 및 조정하세요.
  • 매출로 이어지는 키워드와 그렇지 않은 키워드를 분석하여 타겟팅을 정교화하고 광고비를 극대화하세요.

사례 연구: PostAffiliatePro의 접근법

PostAffiliatePro는 매달 광고비 집행에서 원하는 ROI를 얻지 못해 어려움을 겪고 있었습니다. 이들은 문제 해결을 위해 AI 도입을 결정했습니다. AI 기반 도구를 도입한 이후, 키워드 관리가 자동화되어 긍정/부정 키워드를 더욱 정확하게 식별할 수 있었습니다. 이 변화로 광고비를 최적화하고 비용을 크게 절감했으며, 캠페인 효율도 높아졌습니다. 이 경험은 AI 기술로 키워드 광고비를 효과적으로 관리할 수 있음을 보여줍니다. 각 신규 키워드에 대한 분석은 첫 노출 후 1시간 이내에 진행되어, 방문자가 Google 광고를 클릭하기 전에 부정 키워드를 신속히 차단할 수 있습니다.

improved conversion rate 전환율 개선(관련성 높은 검색만 더 많은 매출을 유도합니다)

추가 자료

효과적인 키워드 관리와 AI 최적화에 대해 더 알고 싶다면, 다음 자료를 참고하세요:

신규 키워드 평가를 위한 Google Ads 스크립트

아래는 키워드 클러스터 평가를 위해 매 시간 실행하는 저희의 스크립트입니다.

이 스크립트는 Google Ads 캠페인 관리를 위한 여러 작업을 자동화합니다. 설정 및 구성을 위해 Google Sheets와 연동되고, Google Ads 계정에서 검색어 분석, 키워드 추가/제외, 그리고 FlowHunt API를 통한 AI 기반 키워드 클러스터링 작업을 수행합니다.

Google Sheet to manage script settings 스크립트 설정 관리를 위한 Google Sheet

Negative keywords automatically applied to Ad groups 부정 키워드가 광고 그룹에 자동으로 적용됨

메인 함수

  • 핵심 제어 로직은 main() 함수에 있습니다. 이 함수는 spreadsheetURL에 명시된 Google Sheets 문서를 열고, apiKey, country, language 등 필요한 설정 정보를 불러옵니다.
  • 시스템은 먼저 신규 긍정 키워드를 FlowHunt 클러스터에 추가하며, 성공하면 할당되지 않은 검색어를 분석합니다.

키워드 분석

  • 할당되지 않은 단어 분석: 모든 광고 계정의 광고 그룹을 지정된 라벨로 순회하며, 타겟팅되지 않았고 최소 1회 노출된 검색어를 Google Ads에서 가져옵니다.
  • 시스템은 FlowHunt API를 통해 현재 분석 중인 키워드와 유사한 키워드를 찾고, 지정된 minimumMatch 기준에 따라 필터링합니다.
  • 기준에 맞는 검색어는 긍정 키워드로 추가되고, 그렇지 않은 경우 부정 키워드로 처리되어 Google Sheet 및 광고 캠페인에 반영됩니다.

FlowHunt 연동

  • API 연동: 스크립트는 callFlowHuntApi() 함수를 통해 FlowHunt API와 연동하여 워크스페이스 ID 조회, 키워드 클러스터링 등을 수행합니다.
  • 클러스터에 키워드 추가: 긍정 키워드를 FlowHunt로 전송하여 실시간 Google Ads 검색 데이터 기반으로 클러스터링합니다.
  • 추가/부정 키워드는 별도 시트에 기록되어 지속적인 모니터링 및 검토가 가능합니다.

사용 방법

이 스크립트를 배포하려면, 다음 단계를 따라야 합니다:

  • 유효한 Google Sheets URL을 제공하고, 필요 시트(“Settings”, “AddedKW”, “NegativeKW”)가 존재하는지 확인하세요.
  • Google Sheets에서 FlowHunt API 키, 국가 코드 등 운영 설정을 올바르게 구성하세요.
  • Google Ads Script 환경에서 API 접근 권한이 활성화된 상태로 스크립트를 실행하세요.

Add script to your Google Ads in menu Tools -> Bulk Actions -> Scripts Google Ads의 Tools -> Bulk Actions -> Scripts 메뉴에서 스크립트를 추가하세요.

실제 Google Sheet 문서의 링크를 꼭 입력해야 합니다. 나머지는 저희가 책임집니다. 캠페인에 속한 키워드를 식별하고, 부정/긍정 키워드 모두를 자동으로 관리합니다.

부정 키워드 자동 관리를 위한 Google Ads 스크립트

//Global variables
var spreadsheetURL;
var spreadsheet;
var sheetSettings; 
var sheetAddedKW;
var sheetNegativeKW;
var apiKey;
var labelName;
var country;
var language;
var location;
var urlsCount;
var minimumMatch;
var workspaceId;

function main() {
    // Provide the Google Sheets URL here
  spreadsheetURL = "https://docs.google.com/spreadsheets/d/....... FULL URL TO GOOGLE SHEET";
  spreadsheet = SpreadsheetApp.openByUrl(spreadsheetURL);
  sheetSettings = spreadsheet.getSheetByName("Settings"); 
  sheetAddedKW = spreadsheet.getSheetByName("AddedKW");
  sheetNegativeKW = spreadsheet.getSheetByName("NegativeKW");
  apiKey = getSettingValue("FlowHuntAPIkey")
  labelName = getSettingValue("LabelName")
  country = getSettingValue("CountryCode")
  language = getSettingValue("LanguageCode")
  location = getSettingValue("Location")

  urlsCount = getSettingValue("TopUrlsCount")
  minimumMatch = getSettingValue("MinimumMatch")
  workspaceId = getWorkspaceId()
  
  if (workspaceId.length < 10) {
    Logger.log("Failed to load workspace id from FlowHunt, check API key");
    return;
  }
  
  Logger.log("FlowHunt WorkspaceId: " + workspaceId);
  
  if (addPositiveKWsToCluster() == 0) {
    // Analyze new keywords just if all positive keywords added already
    analyzeNotAssignedWords();
  }
}

function analyzeNotAssignedWords() {
  Logger.log("*** START Checking not assigned keywords");
  
  // Iterate through all ad groups in the account
  var adGroupsIterator = AdsApp.adGroups().get();
  
  while (adGroupsIterator.hasNext()) {
    var adGroup = adGroupsIterator.next();
    var groupName = adGroup.getId() + " - " + adGroup.getName();
    if (hasLabel(adGroup, labelName)) {
      // Get the search terms for the current ad group ordered by clicks in the last X days
      var searchTermsQuery = "SELECT Query FROM SEARCH_QUERY_PERFORMANCE_REPORT " +
        "WHERE AdGroupId = " + adGroup.getId() +
        " AND QueryTargetingStatus = \"NONE\" " +
        "DURING TODAY";

      var searchTermsIterator = AdsApp.report(searchTermsQuery).rows();
      var adGroupKeywords = [];
      while (searchTermsIterator.hasNext()) {
        var searchTerm = searchTermsIterator.next();
        var searchTermText = searchTerm["Query"].trim();
        var similarQueries = getSimilarQueries(groupName, searchTermText)
        var filteredSimilarQueries = getFilteredSimilarQueries(similarQueries);
        if (filteredSimilarQueries.length > 0) {
          var keywordOperation = adGroup.newKeywordBuilder().withText("[" + searchTermText + "]").build();
          if (keywordOperation.isSuccessful()) {
            adGroupKeywords.push(searchTermText);
            var rowData = [groupName, searchTermText, new Date(), "ADDING AS POSITIVE, REVIEW!", JSON.stringify(filteredSimilarQueries)];
            sheetAddedKW.appendRow(rowData);
          } else {
            Logger.log("Failed to add keyword as positive:" + searchTermText)
          }
        } else {
          // add to negative
           adGroup.createNegativeKeyword("[" + searchTermText + "]");
          Logger.log("Excluded search term in ad group '" + groupName + "': " + searchTermText);
          var rowData = [groupName, "[" + searchTermText + "]", new Date(), JSON.stringify(similarQueries)];
          sheetNegativeKW.appendRow(rowData);
        }
      }
      if (adGroupKeywords.length > 0) {
        //Add all keywords in the list to FlowHunt Cluster
        addKeywordsToFlowHunt(groupName, adGroupKeywords);
      }
    }
  }
  Logger.log("*** FINISHED Checking not assigned keywords");
}

function getSimilarQueries(groupName, query) {
  result = callFlowHuntApi("/serp/serp/cluster/query_intersections?workspace_id="+workspaceId, "POST", {
    "query": query,
    "country": country,
    "language": language,
    "location": location,
    "group_name": groupName,
    "live_mode": true,
    "max_position": urlsCount
  });
  Logger.log(result)
  if (result.status=="SUCCESS") {
    return JSON.parse(result.result);
  }
  return []
}

function getFilteredSimilarQueries(similarQueries) {
  filtered = [];
  for (var i=1; i<similarQueries.length; i++){
    if (similarQueries[i].count>=minimumMatch) {
      filtered.push(similarQueries[i]);
    }
  }
  return filtered;
}

function addPositiveKWsToCluster() {
  Logger.log("*** START Checking new campaign keywords");
  // Iterate through all ad groups in the account
  var adGroupsIterator = AdsApp.adGroups().get();
  var processedKWs = sheetAddedKW.getDataRange().getValues();
  var processedKWsMap = {};
  var rowsAdded = 0;
  
  for (var i = 1; i < processedKWs.length; i++) { // Start at 1 to skip header row if exists
    var groupName = processedKWs[i][0];
    var keyword = processedKWs[i][1];
    processedKWsMap[groupName + '|' + keyword] = true;
  }
  
  while (adGroupsIterator.hasNext()) {
    var adGroup = adGroupsIterator.next();
    var groupName = adGroup.getId() + " - " + adGroup.getName();
    if (hasLabel(adGroup, labelName)) {
      var keywordsIterator = adGroup.keywords().get();
      var adGroupKeywords = [];
      while (keywordsIterator.hasNext()) {
        var keyword = keywordsIterator.next();
        if (keyword.isEnabled()) {
          var key = groupName + '|' + keyword.getText();
          if (!processedKWsMap[key]) {
            adGroupKeywords.push(keyword.getText());
            var rowData = [groupName, keyword.getText(), new Date(), "Already present in campaign"];
            sheetAddedKW.appendRow(rowData);
            processedKWsMap[key] = true; 
          }
        }
      }
      if (adGroupKeywords.length > 0) {
        //Add all keywords in the list to FlowHunt Cluster
        addKeywordsToFlowHunt(groupName, adGroupKeywords);
      } else {
        Logger.log("No new keywords in Group: " + groupName);
      }
      rowsAdded = rowsAdded + adGroupKeywords.length
    }
  }
  Logger.log("*** FINISHED Checking new campaign keywords");
  return rowsAdded;
}

function addKeywordsToFlowHunt(GroupName, adGroupKeywords) {
  requests = []
  adGroupKeywords.forEach(function(keyword) {
    requests.push(
        {
          "query": keyword,
          "country": country,
          "language": language,
          "location": location,
          "group_name": GroupName,
          "count_urls": 30
        }
      );
    });
  callFlowHuntApi("/serp/serp/cluster/add_queries?workspace_id="+workspaceId, "POST", {"requests":requests});
}

function getSettingValue(settingName) {
    var data = sheetSettings.getDataRange().getValues();
    for (var i = 0; i < data.length; i++) {
        if (data[i][0] === settingName) {
            return data[i][1];
        }
    }
    return null;
}
  
function getWorkspaceId() {
  result = callFlowHuntApi("/auth/me", "GET")
  if (result !== null) {
    return result.api_key_workspace_id;
  }
}

function callFlowHuntApi(endpoint, method, requestBody) {
    var url = "https://api.flowhunt.io/v2" + endpoint;
    var headers = {
        "Api-Key": apiKey,
        "Content-Type": "application/json"
    };
    var options = {
        "method" : method,  // or "post", "put", etc.
        "headers" : headers,
        "payload": JSON.stringify(requestBody)
    };
    
    try {
        var response = UrlFetchApp.fetch(url, options);
        var responseData = JSON.parse(response.getContentText());
        Logger.log(responseData);
        return responseData;
    } catch (e) {
        Logger.log("An error occurred: " + e.message);
    }
    return null;
}

function hasLabel(adGroup, labelName) {
  var labels = adGroup.labels().get();
  while (labels.hasNext()) {
    var label = labels.next();
    if (label.getName() === labelName) {
      Logger.log("Processing Adgroup " + adGroup.getName());
      return true;
    }
  }
  return false;
}

자주 묻는 질문

Google Ads에서 부정 키워드는 왜 중요한가요?

부정 키워드는 광고가 관련 없는 검색에 노출되는 것을 막아 불필요한 비용을 줄이고, 가장 관련성 높은 쿼리에만 집중함으로써 캠페인 ROI를 향상시킵니다.

AI는 부정 키워드 관리를 어떻게 자동화하나요?

FlowHunt와 같은 AI 도구는 실시간 검색 데이터를 분석하여 관련 없는 키워드를 식별하고, 부정 키워드를 캠페인에 자동으로 반영하여 시간과 효율을 모두 절약합니다.

AI로 부정 키워드를 자동화하면 어떤 결과를 기대할 수 있나요?

전환율 증가, 관련 없는 클릭에 사용되는 광고비 감소, 그리고 AI가 키워드 리스트와 타겟팅을 지속적으로 최적화함에 따라 캠페인 효율이 향상됩니다.

내 Google Ads에 FlowHunt 자동화를 어떻게 설정하나요?

Google Ads 계정을 연결하고, Google Sheet에서 설정을 구성한 뒤, 제공된 스크립트를 배포하면 FlowHunt의 AI로 자동 키워드 관리가 활성화됩니다.

빅토르 제만은 QualityUnit의 공동 소유주입니다. 20년이 넘는 기간 동안 회사를 이끌어왔지만, 여전히 주로 소프트웨어 엔지니어로서 AI, 프로그램적 SEO, 백엔드 개발을 전문으로 하고 있습니다. 그는 LiveAgent, PostAffiliatePro, FlowHunt, UrlsLab 등 수많은 프로젝트에 기여해왔습니다.

빅토르 제만
빅토르 제만
CEO, AI 엔지니어

AI로 Google Ads를 자동화하세요

Google Ads ROI를 극대화할 준비가 되셨나요? AI 기반 자동화가 부정 키워드를 관리하고 광고비를 최적화하는 방법을 확인해보세요.

더 알아보기

부정 쿼리 자동화를 통한 PPC AI 에이전트
부정 쿼리 자동화를 통한 PPC AI 에이전트

부정 쿼리 자동화를 통한 PPC AI 에이전트

FlowHunt의 PPC AI 에이전트로 Google Ads의 부정 키워드를 자동화하세요. 관련 없는 쿼리를 제외하고 불필요한 비용을 줄이며 AI 기반 타겟팅과 손쉬운 캠페인 최적화로 전환율을 향상시킵니다....

2 분 읽기
PPC AI +3
검색어 격리는 PPC 광고 최적화에 필수적입니다
검색어 격리는 PPC 광고 최적화에 필수적입니다

검색어 격리는 PPC 광고 최적화에 필수적입니다

검색어 격리가 PPC 광고 최적화에 왜 중요한지 알아보세요. 상위 성과 검색어를 타겟팅하고, ROI를 높이며, 비용을 절감하고, 매치 타입, 제외 키워드 및 자동화 도구를 활용해 캠페인을 간소화하는 방법을 소개합니다....

6 분 읽기
PPC Search Term Isolation +5
PPC 최적화와 키워드 그룹화 이해하기
PPC 최적화와 키워드 그룹화 이해하기

PPC 최적화와 키워드 그룹화 이해하기

PPC 캠페인을 최적화하고 키워드 그룹화로 더 높은 연관성, 향상된 품질 점수, 더 나은 ROI, 효과적인 캠페인 관리를 달성하는 방법을 알아보세요. 광고 그룹 구조화, 랜딩 페이지 정렬, 제외 키워드 활용을 위한 실질적인 팁, 도구, 모범 사례를 확인하세요....

8 분 읽기
PPC Keyword Grouping +4