
ネガティブクエリ自動化によるPPC AIエージェント
FlowHuntのPPC AIエージェントでGoogle広告のネガティブキーワードを自動化。無関係なクエリを除外し、無駄な広告費を削減、AIによるターゲティングと手間のかからないキャンペーン最適化でコンバージョンを向上させます。...
FlowHuntはAIを活用してGoogle広告の除外キーワード管理を自動化し、企業のコスト削減、広告費の最適化、そしてキャンペーン成果の向上をサポートします。
無駄なキーワード費用とは、あなたの広告が実際に販売している商品やサービスと合わない検索結果に表示されてしまうことで発生します。こうした無関係なクリックは、売上につながらないのに費用だけがかかってしまい、予算をすぐに消費してしまいます。たとえば、高級レザーシューズを販売する会社が「靴を買う」のような幅広いキーワードを設定した場合、スニーカーやサンダルを探している人からのクリックも集めてしまい、本来のターゲットではない顧客に広告費が使われてしまいます。このようなキーワードのミスマッチは、広告費の無駄遣いやROIの低下につながります。無駄な支出を避け、適切なキーワードに予算を集中させるためにも、こうした仕組みを理解することが重要です。
除外キーワードは、すべてのGoogle広告キャンペーンにとって不可欠なツールです。広告主は、特定の検索語句を除外キーワードとして設定することで、無関係な検索では広告が表示されないようにできます。たとえば、「安い」や「割引」などを除外キーワードにすることで、高級レザーシューズの会社は、プレミアム商品に興味のないユーザーからのクリックを避けることができます。除外キーワードを丁寧にリストアップすることで、広告費の最適化、無駄なクリックの削減、そしてキャンペーン全体の効果向上が期待できます。
人工知能(AI)は、Google広告キャンペーンの管理方法を大きく変えつつあります。FlowHuntのようなAIツールは、キーワードのグルーピングに特化しており、関連キーワードの特定と整理をより効率的に行えます。これにより、ポジティブ(狙いたい)キーワードも除外キーワードも、手作業による管理の負担を大幅に減らすことができます。AI主導のキーワード管理は、パフォーマンスデータに基づきリアルタイムで変更を加えることができるため、広告費を常に最適化し、最大のROIを実現します。
無駄なキーワード費用を削減するには、以下の戦略を取り入れましょう:
PostAffiliateProは、毎月の広告費に課題を抱え、Google広告キャンペーンから思うようなROIが得られていませんでした。そこでAIの導入を決断。AI駆動のツールを取り入れることで、キーワード管理プロセスを自動化し、ポジティブ・ネガティブ両方のキーワードをより正確に特定しました。この変化により、広告費を最適化し、コストを大幅に削減、キャンペーン効率も向上しました。新しいキーワードの分析は、最初のインプレッションから1時間以内に実行されます。このスピード感は、訪問者がGoogle広告をクリックする前に、除外すべきキーワードを素早く検出するのに役立ちます。
効果的なキーワード管理やAI最適化についてさらに学びたい方は、以下のリソースもご覧ください:
以下は、キーワードクラスタを評価するために毎時実行しているスクリプトです。
このスクリプトは、Google広告キャンペーン管理に関するさまざまなタスクを自動化することを目的としています。設定用のGoogleスプレッドシートと連携し、検索語句の分析やキーワードの追加・除外、さらに高度なAIキーワードクラスタリングのためにFlowHunt APIとの連携を行います。
main()
関数に格納されています。この関数は、spreadsheetURL
で指定されたGoogleスプレッドシートを開き、apiKey
やcountry
、language
など必要な設定を取得します。minimumMatch
基準でフィルタリングします。callFlowHuntApi()
関数により、ワークスペースIDの取得やキーワードクラスタリングなど、さまざまなタスクをFlowHunt APIとやり取りします。このスクリプトを導入するには、以下の手順が必要です:
Googleスプレッドシートへの実際のリンクを設定するのをお忘れなく。あとは私たちの魔法にお任せください。キャンペーンに属するキーワードを検出し、(ポジティブ・ネガティブ両方の)キーワード管理を自動化します。
//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;
}
除外キーワードを使うことで、広告が無関係な検索に表示されるのを防ぎ、無駄な費用を削減し、本当に関連性の高い検索に絞ってROIを向上させることができます。
FlowHuntのようなAIツールはリアルタイムの検索データを分析し、無関係なキーワードを特定、自動的に除外キーワードとしてキャンペーンに追加することで、手間を省き効率を向上させます。
AIが継続的にキーワードリストやターゲティングを最適化することで、コンバージョン率の向上、無関係なクリックによる広告費の削減、キャンペーンの効率アップが期待できます。
Google広告アカウントを接続し、Googleスプレッドシート上で設定を行い、提供されるスクリプトをデプロイすることで、FlowHuntのAIによる自動キーワード管理が利用できます。
ヴィクトル・ゼマンはQualityUnitの共同所有者です。20年以上会社を率いてきた今も、主にソフトウェアエンジニアとして、AI、プログラム的SEO、バックエンド開発を専門としています。LiveAgent、PostAffiliatePro、FlowHunt、UrlsLabなど、数多くのプロジェクトに貢献してきました。
FlowHuntのPPC AIエージェントでGoogle広告のネガティブキーワードを自動化。無関係なクエリを除外し、無駄な広告費を削減、AIによるターゲティングと手間のかからないキャンペーン最適化でコンバージョンを向上させます。...
検索語句の分離がPPC広告の最適化に不可欠な理由を解説。高パフォーマンスな検索語句をターゲットにし、ROI向上・コスト削減・キャンペーン効率化を、マッチタイプ・除外キーワード・自動化ツールで実現する方法をご紹介します。...
PPCキャンペーンを最適化し、キーワードグルーピングをマスターして高い関連性、品質スコアの向上、より良いROI、効果的なキャンペーン管理を実現する方法を学びましょう。広告グループの構成、ランディングページの連携、除外キーワードの活用など、実践的なヒントやツール、ベストプラクティスをご紹介します。...