Start KnowHow Google Adwords 4 Google Ads Scripts, mit denen Sie Geld & Ressourcen sparen [inkl. Download-Script]

4 Google Ads Scripts, mit denen Sie Geld & Ressourcen sparen [inkl. Download-Script]

Von
Rene Beineke
14.05.2019
Lesedauer: 14 min
4 Google Ads Scripts, mit denen Sie Geld & Ressourcen sparen [inkl. Download-Script]

Google hat seit 2018 das Thema Automatisierungen bei Google Ads stark in den Vordergrund gestellt. Trotzdem ist PPC Management zu einem großen Teil noch immer Handarbeit. Zum einen lassen sich "one-size-fits-all" Algorithmen nie 100%ig auf das eigene Geschäftsmodell anwenden, zum anderen beruht Googles Geschäftsmodell nun mal auf den Ausgaben der Werbetreibenden - nicht auf deren Einnahmen. Will man bei mühsamen, wiederkehrenden oder zeitaufwändigen Aufgaben Ressourcen sparen, kommt man irgendwann an Google Ads Scripts nicht mehr vorbei. Im Folgenden haben wir vier unserer liebsten Scripts gesammelt und für Sie aufbereitet.

Wie werden Google Ads Scripts im Account hinterlegt?

Google Ads Scripts können auf Konto- oder Verwaltungskonto-Ebene hinterlegt werden. Zweiteres hat den Vorteil, dass so bestimmte Vorgänge für viele verschiedene Accounts gleichzeitig automatisieren kann. Die Einrichtung funktioniert bei beiden Arten gleich:

  1. Klicken Sie oben in der Leiste auf Tools (Schraubenschlüssel-Symbol)
  2. Dann unter Bulk-Aktionen auf Scripts
  3. Jetzt befinden Sie sich in der Scripts-Übersicht. Falls noch kein Script im Konto hinterlegt wurde, ist hier noch nicht viel zu sehen. Klicken Sie als Nächstes auf das + Symbol
  4. Es öffnet sich ein Text-Editor: Fügen Sie hier das Script ihrer Wahl ein.
    • Achten Sie darauf, dass Sie die leere Platzhalter-Funktion im Text-Editor vorher entfernen.
  5. Wenn das Script bestimmte Einstellungen benötigt, nehmen Sie diese jetzt vor
  6. Geben Sie dem Script einen eindeutigen Namen und speichern Sie
  7. Als Nächstes muss das Script autorisiert werden (gelbe Leiste oben)
    • Dies ist wichtig, da Scripts Änderungen am Konto durchführen können und dafür eine separate Freigabe benötigen.
  8.  Nun können Sie eine Vorschau durchführen, um zu testen, ob alles funktioniert.
    • Achten Sie hierbei auf die Änderungen und das Protokoll. Die Änderungen zeigen die eigentlichen Vorgänge im Konto, die Protokolle Fehler oder Logs.
  9. Nun können Sie das Script entweder direkt durchführen oder für später planen. Eine regelmäßige Durchführung (z.B. wöchentlich) ist natürlich auch möglich.
Wie man Google Ads Scripts einrichtet

So richten Sie Google Ads Scripts im Konto ein

Landing Page Checker: Klicks auf fehlerhafte Seiten vermeiden

Bei großen Google Ads Accounts steht man häufig vor der Frage, wie man sicherstellen kann, dass alle Zielseiten noch funktionieren. Gerade wenn es eine Vielzahl an unterschiedlichen Landing Pages gibt, wie zum Beispiel im E-Commerce-Bereich, kann es immer mal wieder vorkommen, dass eine Seite nicht mehr verfügbar oder ein Produkt nicht mehr auf Lager ist. Sobald die Anzahl der Zielseiten in die hunderte oder tausende gerät, ist der Zeitaufwand, der in eine manuelle Kontrolle gesteckt werden muss, oft nicht mehr verhältnismäßig. Google crawlt die Landing Pages natürlich auch regelmäßig und lehnt Anzeigen mit nicht funktionierenden Zielen konsequent ab, für alle Klicks, die bis dahin entstanden sind, muss man jedoch trotzdem bezahlen.

Google Ads Scripts bieten hierfür jedoch eine Lösung: Die Klasse HTTP Response (gibt Inhalte von URL abfragen wieder) und deren Methoden getContentText (gibt den Quelltext wieder), sowie getResponseCode (gibt den Statuscode wieder). Mit diesen Bausteinen lässt sich ein relativ einfaches Script gestalten, dass alle Zielseiten in einem Google Ads Account auf folgende Aspekte kontrolliert und dann eine E-Mail mit einer Liste aller problematischen URLs verschickt.

  • Ungewünschte Status Codes: Zum Beispiel 404 oder 302
  • Auffällige Phrasen, die auf Probleme hinweisen: Zum Beispiel: "Ausverkauft", "Ein Problem ist aufgetreten" oder "nicht auf Lager".

Wir haben eine Vorlage entworfen, die von jedem Google Ads Account Manager gänzlich ohne Programmier-Kenntnisse genutzt werden kann. Passen Sie einfach die Grundeinstellungen in den ersten Zeilen (über dem TrafficDesign-Logo) an und geben Sie im Google Ads Konto an, in welchem Rhythmus das Script ausgeführt werden soll (z.B. wöchentlich). Vergessen Sie nicht, oben im Script max@mustermann.de durch Ihre richtige E-Mail Adresse auszutauschen, damit Google weiß, wohin der Bericht geschickt werden soll.

/**
*
* Landing Page Checker
*
* Version: 1.0 (29.04.2019)
*
* Google Ads Script um Landing Pages auf bestimmte Wörter (z.B. "Ausverkauft") und Status Codes (404) zu überprüfen.
*
* Das Script steht zur freien Verfüfung, kann kommerziell genutzt und geändert werden. Ursprüngliche Erstellung: trafficdesign.de
*
**/

function main() {

  // An diese Adresse wird eine E-Mail allen problematischen Landing Pages geschickt.
  // Eingabe: ["info@trafficdesign.de"] oder ["a@b.de","c@d.com","e@g.de"]
  // Leer lassen um diesen Schritt zu überspringen.
  var recipients = ["max@mustermann.de"];

  // Nach welchen Wörtern oder Phrasen soll das Script in Quellcode der Landing Page suchen?
  // Wie folgt eingeben: ["Out of stock", "<em>0 available</em>"]
  var messagesToCheckFor = ["traffic", "design"];

  // Nach welchen Fehler Codes soll das Script suchen. Mehr dazu hier: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
  var bad_codes = [
    300, 302, 303, 304, 305, 306, 307, 308,
    400, 401, 402, 403, 404, 405, 406, 407, 408, 409,
    410, 411, 412, 413, 414, 415, 416, 417, 418, 419,
    421, 422, 423, 424, 426, 428, 429,
    431,
    451,
    500, 501, 502, 503, 504, 505, 506, 507, 508, 509,
    510, 511];

  // Sollen Parmaeter (die z.B. für Tracking verwendet werden) aus den Urls entfernt werden?
  // Engabe: true oder false
  var trimAtQuestionMark = true;

  // Werden die Landing Pages im Konto über Anzeigen oder Keywords definiert
  // Eingabe: ads oder keywords
  var type = "ads";

  // Status-Filter
  // ["ENABLED"], ["PAUSED"] oder ["ENABLED","PAUSED"]

  // Kampagnenstatus
  var campaignStatus = ["ENABLED"];

  // Anzeigengruppenstatus
  var adGroupStatus = ["ENABLED"];

  // Keyowrd/Ad-Status
  var status = ["ENABLED"];

  // Optionale Filter
  // Eingabe: ["beispiel1", "beispiel2"]
  // Leer lassen [] zum überspringen

  // Nur auf Kampagnen in deren Namen eine dieser Phrasen vorkommt anwenden.
  var containsArray = [];

  //  Kampagnen in deren Namen eine dieser Phrasen vorkommt werden ignoriert
  var excludesArray = [];

  // Nur Keyowrds/Ads mit diesen Labels checken
  // Case sensitive.
  var labelArray = [];

/**
*   _____         ___ ___ _     ____          _
*  |_   _|___ ___|  _|  _|_|___|    \ ___ ___|_|___ ___
*    | | |  _| .'|  _|  _| |  _|  |  | -_|_ -| | . |   |
*    |_| |_| |__,|_| |_| |_|___|____/|___|___|_|_  |_|_|
*                                              |___|
*
* www.trafficdesign.de | info@trafficdesign.de
*
**/

  var urls = [];
  var bad_lps = [];
  var bad_statuses = [];
  var urlFetchOptions = {muteHttpExceptions: true};
  var countEntities = 0;


  var conditions = [];
  if (containsArray.length > 0) {
    conditions.push(" where the campaign name contains " + containsArray.join(", "));
  }
  if (excludesArray.length > 0) {
    conditions.push(" where the campaign name excludes " + excludesArray.join(", "));
  }
  if (labelArray.length > 0) {
    conditions.push(" where the " + type + " are labelled " + labelArray.join(", "));
  }

  if (containsArray.length === 0) {
    containsArray.push("");
  }

  for(var i = 0; i < containsArray.length; i++){
    var string = iteratorConstructor(type, containsArray[i], excludesArray, labelArray, status, campaignStatus, adGroupStatus);
    eval(string);
    countEntities += iterator.totalNumEntities();
    excludesArray.push(containsArray[i]);
    while(iterator.hasNext()){
      var object = iterator.next();
      var url = object.urls().getFinalUrl();

      if(url == null || url == undefined){
        url = object.getDestinationUrl();
      }

      if(url !== null && url !== undefined){
        if(trimAtQuestionMark){
          url = url.split('?')[0];
        }
        if(urls.indexOf(url) === -1) {
          urls.push(url);
        }
      }
    }
  }

  if (countEntities == 0) {
    throw "No " + type + " found" + conditions.join("; and");
  }
  Logger.log(countEntities + " " + type + " found" + conditions.join("; and"));
  Logger.log(urls.length + " unique URLs to check.");

  for(var x in urls){
    var response = UrlFetchApp.fetch(urls[x],urlFetchOptions);
    var content = response.getContentText();
    var code = response.getResponseCode();
    for(var y = 0; y < messagesToCheckFor.length; y++){
      var message = messagesToCheckFor[y];
      if(bad_codes.indexOf(code) !== -1) {
        bad_statuses.push(urls[x]);
        break;
      }
      if(content.indexOf(message) !== -1){
        bad_lps.push(urls[x]);
        break;
      }
    }
  }

  if ((bad_lps.length === 0) && (bad_statuses.length === 0)) {
    Logger.log("No bad Landing Pages found.");
  } else {
    Logger.log(bad_statuses.length + " lps with bad statuses found:");
    Logger.log(bad_statuses.join("\n"));
    Logger.log(bad_lps.length + " lps with bad phrases found:");
    Logger.log(bad_lps.join("\n"));

  }

  if((recipients.length > 0 && bad_lps.length > 0) || (recipients.length > 0 && bad_statuses.length > 0)) {
    var name = AdWordsApp.currentAccount().getName();
    var subject = name + " - Google Ads: Landing Page Checker ";
    var body = 'Folgende Zielseiten haben mit einem problematischen Status Code geantwortet oder es wurde eine der folgenden Phrasen/Keywords im Quelltext gefunden. \n\n"' + messagesToCheckFor.join('",\n"') + '"\n\nURLs:\n';
    body += bad_statuses.join("\n");
    body += bad_lps.join("\n");
    MailApp.sendEmail(recipients.join(","),subject,body);
    Logger.log("Email sent to " + recipients.join(", "));
  }

  function iteratorConstructor(type, containsString, excludesArray, labelArray, status, campaignStatus, adGroupStatus){

    var string = "var iterator = AdWordsApp."+type+"()";
    if (containsString != "") {
      string = string + ".withCondition('CampaignName CONTAINS_IGNORE_CASE " + '"' + containsString + '"' + "')";
    }
    for(var i = 0; i < excludesArray.length; i++){
      string = string + ".withCondition('CampaignName DOES_NOT_CONTAIN_IGNORE_CASE " + '"' + excludesArray[i] + '"' + "')";
    }
    if(labelArray.length > 0){
      string = string + ".withCondition('LabelNames CONTAINS_ANY " + '["' + labelArray.join('","') + '"]' + "')";
    }

    string = string + ".withCondition('Status IN [" + status.join(",") + "]')";
    string = string + ".withCondition('CampaignStatus IN [" + campaignStatus.join(",") + "]')";
    string = string + ".withCondition('AdGroupStatus IN [" + adGroupStatus.join(",") + "]')";
    string = string + ".orderBy('Cost DESC').forDateRange('LAST_30_DAYS')";
    string = string + ".withLimit(50000)";

    string = string + ".get();";

    return string;

  }

}
 

Smart Auto-Bidder: Automatische Gebotserhöhung basierend auf Wert pro Kosten und Kosten pro Konversion 

Der Smart Auto-Bidder ist so etwas, wie ein semi-automatisches Bid Management Tool. Bei der Benutzung sollte man deshalb vorsichtig sein, da bei falscher Benutzung eventuell die CPCs ungewollt maximiert werden. Der Auto-Bidder ist in der Lage, die Gebote in einem Account (oder in bestimmten Kampagnen) auf Basis der folgenden Metriken zu erhöhen:

  • Wert pro Kosten
  • Kosten pro Konversion

In den Script-Einstellungen können Sie auswählen, auf welche Metrik optimiert werden soll, wie Ihre Zielwerte definiert sind und um wie viel Prozent die Gebote pro Durchführung (z.B. einmal die Woche) erhöht werden soll. Zusätzlich labeled das Script alle modifizierten Keywords, sodass Sie diese bei Bedarf manuell kontrollieren können.    

/**
*
* Google Ads Script um Google Ads Search und Shopping CPCs in der Masse anzupassen.
*
* Das Script steht zur freien Verfüfung, kann kommerziell genutzt und geändert werden. Ursprüngliche Erstellung: trafficdesign.de
*
**/

// SETTINGS

// Bei Ja/Nein-Einstellungen ist immer 1 = Ja und 0 = Nein

// Soll nach Kampagnen gefiltert werden? (1=Ja, 0=Nein)
var campaignFilter = 1;

// Wenn gefiltert werden soll, gebe hier den NAmen der Kampagne ein
var campaignFilterName = "c_1 Veranstaltungen Köln";

// Name des Labels, welches markiert, dass etwas gemacht wurde (Standard ist td_b)
var labelName = "td_b";

// Keywords mit Kosten von über X innerhalb der letzten 7 Tage werden nicht geändert.
// Das ist wichtig, wenn man z.B. alle Keywords über X Euro manuell bearbeiten möchte, alle anderen aber per Script
var costTreshhold = 10.00;

// Das maximale Gebot, auf welches das Script hochbietet
var maxCPC = 5.00;

// Um wieviel % der CPC pro Script-Durchfürhung erhöht werden soll (1.25 = 25%)
var perUp = 1.25;

// WK-Bidding

// Soll sollen Gebote auf CPA-Basis erhöt werden? (1=Ja, 0=Nein)
var wkBidding = 0;

// Der Ziel-CPA mit der wir arbeiten
var targetWK = 7.5;

// CPA-Bidding

// Soll sollen Gebote auf CPA-Basis erhöt werden? (1=Ja, 0=Nein)
var cpaBidding = 0;

// Der Ziel-CPA mit der wir arbeiten
var targetCPA = 2.5;

// ImpressionShare-Bidding

/**
*
* Smart Auto-Bidder
*
* Version: 1.1 (03.05.2019)
*
* Google Ads Script um Google Ads Search und Shopping CPCs in der Masse anzupassen.
*
* Das Script steht zur freien Verfüfung, kann kommerziell genutzt und geändert werden. Ursprüngliche Erstellung: trafficdesign.de
*
**/

// SETTINGS

// Bei Ja/Nein-Einstellungen ist immer 1 = Ja und 0 = Nein

// Zeitraum der Daten: Standard ist LAST_7_DAYS. Weitere Möglichkeiten: TODAY, YESTERDAY, LAST_7_DAYS, THIS_WEEK_SUN_TODAY, LAST_WEEK, LAST_14_DAYS, LAST_30_DAYS, LAST_BUSINESS_WEEK, LAST_WEEK_SUN_SAT, THIS_MONTH, LAST_MONTH, ALL_TIME.
var timespan = "LAST_7_DAYS";

// Soll nach Kampagnen gefiltert werden? (1=Ja, 0=Nein)
var campaignFilter = 0;

// Wenn gefiltert werden soll, gebe hier den NAmen der Kampagne ein
var campaignFilterName = "";

// Name des Labels, welches markiert, dass etwas gemacht wurde (Standard ist td_b)
var labelName = "td_b";

// Keywords mit Kosten von über X innerhalb der letzten 7 Tage werden nicht geändert.
// Das ist wichtig, wenn man z.B. alle Keywords über X Euro manuell bearbeiten möchte, alle anderen aber per Script
var costTreshhold = 10.00;

// Das maximale Gebot, auf welches das Script hochbietet
var maxCPC = 5.00;

// Um wieviel % der CPC pro Script-Durchfürhung erhöht werden soll (1.25 = 25%)
var perUp = 1.25;

// WK-Bidding

// Soll sollen Gebote auf CPA-Basis erhöt werden? (1=Ja, 0=Nein)
var wkBidding = 1;

// Der Ziel-CPA mit der wir arbeiten
var targetWK = 7.5;

// CPA-Bidding

// Soll sollen Gebote auf CPA-Basis erhöt werden? (1=Ja, 0=Nein)
var cpaBidding = 0;

// Der Ziel-CPA mit der wir arbeiten
var targetCPA = 2.5;

/**
*   _____         ___ ___ _     ____          _
*  |_   _|___ ___|  _|  _|_|___|    \ ___ ___|_|___ ___
*    | | |  _| .'|  _|  _| |  _|  |  | -_|_ -| | . |   |
*    |_| |_| |__,|_| |_| |_|___|____/|___|___|_|_  |_|_|
*                                              |___|
*
* www.trafficdesign.de | info@trafficdesign.de
*
**/

function main() {
  getdate();
  updateLabel();
  if (wkBidding == 1) {
    wkAutoBidding();
  }
  if (cpaBidding == 1) {
    cpaAutoBidding();
  }
}

function getdate() {
  var date = new Date();
  printDate = Utilities.formatDate(date, 'Europe/Berlin', 'yyMMdd');
  Logger.log("Datum: " + printDate + "\n\n");
}

function updateLabel() {
  var labelIterator = AdsApp.labels()
    .withCondition("Name CONTAINS '"+labelName+"'")
    .get();
  if (labelIterator.hasNext()) {
    var label = labelIterator.next();
    Logger.log('Cleaning up old Labels...' + "\n\n");
    Logger.log('Name: ' + label.getName());
    Logger.log('Number of campaigns: ' +
      label.campaigns().get().totalNumEntities());
    Logger.log('Number of ad groups: ' +
      label.adGroups().get().totalNumEntities());
    Logger.log('Number of ads: ' + label.ads().get().totalNumEntities());
    Logger.log('Number of keywords: ' +
      label.keywords().get().totalNumEntities());
    label.remove();
    Logger.log('Label removed' + "\n\n");
  }

  labelName = (labelName + "_" + printDate);
  Logger.log('Erstelle neues Label: ' + labelName + "\n\n");
  AdsApp.createLabel(labelName);
}

function wkAutoBidding() {
  Logger.log('Erhöhe CPCs basierend auf WK...' + "\n\n");

  var query = "SELECT CampaignName, AdGroupId, Id, ConversionValue, Cost, Conversions " +
      " FROM KEYWORDS_PERFORMANCE_REPORT " +
      " WHERE " +
      (campaignFilter!=0 ? " CampaignName = '" + campaignFilterName + "' AND " : "") +
      " Conversions > 0 " +
      " DURING " + timespan;
  // Logger.log("Performed Query: " + query + "\n");
  var report = AdsApp.report(query);
  var rows = report.rows();
  var keywords = [];

  // Map of keyword id to WK
  var keywordWK = {};
  // List of all keyword ids ([AdGroupId, Id])
  var keywordIds = [];

  if (!rows.hasNext()) Logger.log("No Keywords found!\n");

  Logger.log("Ziel WK: " + targetWK + "\n\n");
  while (rows.hasNext()) {
    var row = rows.next();
    var kWK = row["ConversionValue"] / row["Cost"];
    // Logger.log("Keyword ID: " + row['Id'] +" - WK: " + kWK + "\n");
    if (kWK > targetWK) {
      row["kWK"] = kWK;
      keywordWK[row["AdGroupId"],row["Id"]] = row;
      keywordIds.push([row["AdGroupId"],row["Id"]]);
    }
  }

  var keywords = AdsApp.keywords().withIds(keywordIds).get();
  while (keywords.hasNext()) {
    var thisKeyword = keywords.next();
    var kwRow = keywordWK[thisKeyword.getAdGroup().getId(),thisKeyword.getId()];
    var currCPC = thisKeyword.bidding().getCpc();

    var newCPC = currCPC; //just set so newCPC always has a default value;
    newCPC = currCPC * perUp; //easy

    thisKeyword.bidding().setCpc(newCPC);
    AdsApp.createLabel(labelName + "_" + printDate);
    thisKeyword.applyLabel(labelName + "_" + printDate);

    Logger.log("Keyword: " + thisKeyword.getText() + "\n" + "alter CPC: " + currCPC + "\n" + "neuer CPC: " + newCPC + "\n" + "neues Label: " + labelName + "_" + printDate + "\n\n");

  }
}

function cpaAutoBidding() {
  var query = AdsApp.keywords()
    .withCondition("CampaignStatus = 'ENABLED'")
    .withCondition("AdGroupStatus = 'ENABLED'")
    .withCondition("Status = 'ENABLED'")
    .withCondition('LabelNames CONTAINS_NONE ["' + labelName + '"]')
    .forDateRange(timespan);

    // Checks if Campaign Filter is active and applies it if necessary
    if (campaignFilter != 0) {
        query.withCondition('CampaignName = "' + campaignFilterName +'"');
    }

    var keywordIter = query.orderBy("Cost DESC").get();

  Logger.log('Erhöhe CPCs basierend auf CPA...' + "\n\n");

  Logger.log("Ziel CPA: " + targetCPA + "\n\n");

  while (keywordIter.hasNext()) {
    var thisKeyword = keywordIter.next();
    // Get Stats der letzten 7 Tage
    var stats = thisKeyword.getStatsFor("LAST_7_DAYS");
    var kConv = stats.getConversions();
    var kCost = stats.getCost();
    var kCPA = 0;
    if ((kCost / kConv) > 0){
      kCPA = (kCost / kConv);
    }

    if(kCPA < targetCPA) { //Wenn der CPA besser ist als der Ziel CPA
      if(kCost > costTreshhold) { //don't change bids for Keywords with cost > X

        kCPA = kCPA.toFixed(2); //set to two decimal places, just for clarity in logging

        var currCPC = thisKeyword.getMaxCpc();
        var newCPC = currCPC; //just set so newCPC always has a default value;

        newCPC = currCPC * perUp; //easy

        //we always want CPC below upper limit
        if(newCPC > maxCPC) {newCPC = maxCPC;}

        newCPC = newCPC.toFixed(2);

        thisKeyword.setMaxCpc(newCPC);
        AdsApp.createLabel(labelName + "_" + printDate);
        thisKeyword.applyLabel(labelName + "_" + printDate);

        Logger.log("Keyword: " + thisKeyword.getText() + "\n" + "CPA: " + kCPA + "\n" + "alter CPC: " + currCPC + "\n" + "neuer CPC: " + newCPC + "\n" + "neues Label: " + labelName + "_" + printDate + "\n\n");
      }
    }
  }
}

CPC-Massenbearbeitung: Kontoweite Gebotsanpassungen leicht gemacht

Etwas bodenständiger, als beim Smart Auto-Bidder, geht es bei der CPC-Massenbearbietung vor: Manchmal will man ganz simpel alle Gebote in einem Konto um einen bestimmten Wert reduzieren. Möchte man zum Beispiel über die Weihnachtsfeiertage alle CPCs in einem Account während einer geplanten Zeitspanne um 50 % reduzieren, merkt man schnell, dass dies einfacher klingt, als es ist.

  • Über automatisierte Regeln lassen sich keine Shopping-Gebote anpassen
  • Über den Google Ads Editor lässt sich die Durchführung nicht schedulen
  • Manuell ist wiederum sehr aufwändig

Deshalb haben wir ein kleines Script erstellt, das wie automatisierte Regeln geplant werden kann und auch für Google Shopping CPCs funktioniert:

/**
*
* CPC-Massenbearbeitung
*
* Version: 1.0 (29.04.2019)
*
* Google Ads Script um Google Ads Search und Shopping CPCs in der Masse anzupassen.
*
* Das Script steht zur freien Verfüfung, kann kommerziell genutzt und geändert werden. Ursprüngliche Erstellung: trafficdesign.de
*
**/

// SETTINGS

// Bei Ja/Nein-Einstellungen ist immer 1 = Ja und 0 = Nein

// um wieviel % soll der Search-CPC pro Script-Durchfürhung angepasst werden? (0.6 = 60 %)
var searchChange = 0.60;

// um wieviel % soll der Shopping-CPC pro Script-Durchfürhung angepasst werden? (0.6 = 60 %)
var shoppingChange = 0.60;

// Soll der CPC erhöht oder verringert werden? (1=erhöht, 0=verringert)
var changeType = 1;

/**
*   _____         ___ ___ _     ____          _
*  |_   _|___ ___|  _|  _|_|___|    \ ___ ___|_|___ ___
*    | | |  _| .'|  _|  _| |  _|  |  | -_|_ -| | . |   |
*    |_| |_| |__,|_| |_| |_|___|____/|___|___|_|_  |_|_|
*                                              |___|
*
* www.trafficdesign.de | info@trafficdesign.de
*
**/

function main() {
  setKeywordCpcBid();
  setShoppingCpcBid();
}

function setKeywordCpcBid() {
  var keywordsToChange = AdsApp.keywords()
    .withCondition('CampaignStatus = ENABLED')
    .withCondition('AdGroupStatus = ENABLED')
    .get();
    while (keywordsToChange.hasNext()) {
        var keyword = keywordsToChange.next();
        if (changeType == 1) {
            keyword.setMaxCpc(keyword.getMaxCpc() * (1 + searchChange));
        } else {
            keyword.setMaxCpc(keyword.getMaxCpc() * (1 - searchChange));
        }
    }
}

function setShoppingCpcBid() {
  var ProductGroupToChange = AdsApp.productGroups()
    .withCondition('CampaignStatus = ENABLED')
    .withCondition('AdGroupStatus = ENABLED')
    .get();
    while (ProductGroupToChange.hasNext()) {
        var productGroup = ProductGroupToChange.next();
        if (changeType == 1) {
            productGroup.setMaxCpc(productGroup.getMaxCpc() * (1 + shoppingChange));
        } else {
            productGroup.setMaxCpc(productGroup.getMaxCpc() * (1 - shoppingChange));
        }
    }
}

Placement-Ausschluss nach Top-Level-Domain: Ungewollte Placements automatisch ausschließen

Google hat die Einstiegshürden bei Display-Kampagnen in den letzten Jahren immer weiter herabgesetzt. Banner-Kampagnen lassen sich mittlerweile leichter aufsetzen als zum Beispiel Google Shopping Kampagnen. Erst im Verlauf der Optimierung (oder mit ein bisschen Erfahrung) fällt einem dann auf, dass für eine gute Performance ganz schön viele Stellschrauben gedreht werden müssen. Gerade bei den Placements muss man je nach Budget besonders engmaschig kontrollieren, wo die Anzeigen ausgespielt wurden. Häufig fällt dann auf, dass im Tab "Wo Anzeigen ausgespielt wurden" viele unpassende URLs erscheinen. Gerade unpassende Top-Level-Domains sind dabei leicht zu identifizieren und können effizient über eine Automatisierung ausgeschlossen werden.

Wollen Sie also pauschal bestimmte Länderkennungen ausschließen (z.B. .ro, .ba, .bg, .br, .cz bei einer Kampagne, deren Targeting eigentlich in anderen Ländern liegt) oder vermeiden, dass Ihre Anzeigen auf den typischen Affiliate-Domains (.top) ausgespielt werden, können wir Ihnen folgendes Script ans Herz legen. Die ursprüngliche Version stammt von Dawson Reid und Andrew Breen (outshine.com). Wir haben diese übersetzt, an die neue Google Ads Version angepasst und ein Bug bei Placements mit einem vorgestellten www. behoben:  

/**
*
* Placement-Ausschluss nach Top-Level-Domain
*
* Version: 1.1 (29.04.2019)
*
* Google Ads Script, welches automatisch ungewollte Display Placements, nach TLD ausschließt (Beispiel: Alle .xyz-Domains). Das Script funktioniert auf Account und auf MCC-Level.
*
* Das Script steht zur freien Verfüfung, kann kommerziell genutzt und geändert werden. Ursprüngliche Erstellung: Dawson Reid und Andrew Breen (https://outshine.com/blog/automate-negative-placement-in-google-display-with-this-script). Überarbeitung: trafficdesign.de
*
**/

// SETTINGS

// Top Level Domains to exclude
var TLDs = '.ro, .ba, .bg, .br, .cz, .es, .gr, .hr, .hu, .it, .me, .nl, .pl, .rs, .ro, .ru, .su, .sk, .tr, .vd, .xyz, .space, .top, .review';

/**
*   _____         ___ ___ _     ____          _
*  |_   _|___ ___|  _|  _|_|___|    \ ___ ___|_|___ ___
*    | | |  _| .'|  _|  _| |  _|  |  | -_|_ -| | . |   |
*    |_| |_| |__,|_| |_| |_|___|____/|___|___|_|_  |_|_|
*                                              |___|
*
* www.trafficdesign.de | info@trafficdesign.de
*
**/

function removePlacementByDomain (domain) {
  var placementSelector = AdsApp.display().placements()
  .withCondition("PlacementUrl CONTAINS '" + domain + "'")
  .withCondition("PlacementUrl DOES_NOT_CONTAIN '" + "www" + domain + "'");

  var placementIterator = placementSelector.get();
  while (placementIterator.hasNext()) {
    var placement = placementIterator.next();
    var placementUrl = placement.getUrl();
    Logger.log(placementUrl);

    var campaign = placement.getCampaign();
    if (!campaign.isRemoved()) {
      var excludeOperation = campaign.display().newPlacementBuilder().withUrl(placementUrl).exclude();
      if (!excludeOperation.isSuccessful()) {
        Logger.log("Konnte nicht ausschließen: " + placementUrl);
      }
    }
  }
}

function run () {
  TLDs.split(',').map(function (tld) {
    return tld.trim();
  }).forEach(function (domain) {
    removePlacementByDomain(domain);
  });
}

function executeInSequence (sequentialIds, executeSequentiallyFunc) {
  Logger.log('Executing in sequence : ' + sequentialIds);
  sequentialIds.forEach(function (accountId) {
    var account = MccApp.accounts().withIds([accountId]).get().next();
    MccApp.select(account);
    executeSequentiallyFunc();
  });
}

function main () {
  try {
    var accountIterator = MccApp.accounts().orderBy('Name').get();
    Logger.log('Accounts im MCC: ' + accountIterator.totalNumEntities());

    var accountIds = [];
    while (accountIterator.hasNext()) {
      var account = accountIterator.next();
      accountIds.push(account.getCustomerId());
    }
    var parallelIds = accountIds.slice(0, 50);
    var sequentialIds = accountIds.slice(50);
    // execute accross accounts
    MccApp.accounts()
      .withIds(parallelIds)
      .executeInParallel('run');
    if (sequentialIds.length > 0) {
      executeInSequence(sequentialIds, run);
    }
  } catch (exception) {
    // not an Mcc
    Logger.log('Start (einzelner Account)');
    run();
  }
}

Fazit

Beim täglichen Google Ads Management kommt man häufig irgendwann an einen Punkt, an dem man sich die Frage stellt, ob man wiederkehrende Aufgaben nicht automatisieren kann. Hat man im Unternehmen jemanden der über grundlegende JavaScript-Kenntnisse verfügt, kann man über Google Ads Scripts mittelfristig häufig wertvolle Ressourcen sparen. Die erste Anlaufstelle ist dann natürlich die offizielle Dokumentation von Google. Hier finden sich auch einige nützliche Beispiele und Vorlagen. Wir haben im Laufe der Zeit unsere eigenen Lösungen implementiert und erweitert und möchten diese gerne der Öffentlichkeit zu Verfügung stellen. Des Weiteren werden wir diese Liste kontinuierlich erweitern. Welche Aufgabe würden Sie zukünftig gerne automatisieren?

https://www.trafficdesign.de/sites/default/files/styles/twittercard/public/twittercard-google-scripts-fuer-reklame_0.jpeg?itok=ZJmh5qWO
Fanden Sie den Artikel hilfreich?
Durchschnitt: 4 (174 votes)
Bild des Benutzers Rene
Rene Beineke
Ich hätte gerne einen Hund, eine Katze, eine Ziege, eine Landschildkröte und ein Flughörnchen, will aber gleichzeitig auch in der Stadt wohnen. Bis dieses Dilemma geklärt ist, konzentriere ich mich auf ausgeklügelte Online Marketing Strategien & die besten Potenziale für unsere Kunden.

Brauchen Sie Unterstützung bei diesem Thema?

Sprechen Sie uns unverbindlich an und lassen Sie sich von uns beraten.

Anfrage schicken »


Kommentieren Sie diesen Artikel!

Schreiben Sie einen Kommentar und Sie bekommen zeitnah eine Rückmeldung von uns.

Kommentar verfassen