Snippet-Erweiterungen automatisiert erstellen

Ein Snippet kommt selten allein
veröffentlicht am: 01.02.2019

Möchte man Snippet-Erweiterungen möglichst genau auf die entsprechenden Anzeigen anpassen, ist die Erstellung dieser oftmals sehr zeitaufwendig. Wir haben dazu ein Skript entwickelt, welches diese automatisiert anhand der Kampagnen- und Anzeigengruppenbezeichnung erstellt. Als wir letztens unsere Inventarkampagnen schön in Search Ads 360 automatisiert erstellt hatten, standen wir vor einem kleinen Problem: wir hatten Unmengen an extrem spezifischen Anzeigengruppen. Dies ist zwar für den Longtail-Bereich sehr sinnvoll, macht die Handhabung der Anzeigenerweiterungen aber schnell sehr komplex. Lassen sich in Search Ads 360 noch automatisch Sitelinks erstellen, gilt dies leider (noch) nicht für Snippet-Erweiterungen. Es musste also eine Lösung her, die im besten Fall automatisch, je nach Inhalt der Anzeigengruppe möglichst spezifische Snippet-Erweiterungen für die verschiedenen Marken erstellt. Was dabei rausgekommen ist, ist das Snippet Builder Script. https://www.instagram.com/p/BsNUgLehc1X/ Dieses lässt sich komplett an die jeweiligen Gegebenheiten des Kontos anpassen. Dafür ist die Konfiguration fast komplett in einer Google Tabelle hinterlegt, welche wiederum mit dem jeweiligen Skript verknüpft ist.

 

Installation des Skriptes

  1. Erstellung eines neuen leeren Skriptes auf Konto-Ebene
  2. Einfügen des Programmcodes in das neu erstellte, leere Skript
  3. Erstellung einer Kopie des Konfiguration Google Tabellenblatts unter "Datei" -> "Kopie erstellen ..."
  4. Hinterlegung der URL des neu kopierten Google Tabellenblattes im Programmcode des Skriptes
  5. Einstellung der restlichen Parameter im Programmcode des Skriptes

Im Google Tabellenblatt wird in den ersten vier Spalten definiert, wo neue Snippet-Erweiterungen erstellt werden sollen. Dabei trägt man in der ersten Spalte eine Zeichenfolge ein, die in der Bezeichnung der Kampagne enthalten sein soll. In der zweiten Spalte hinterlegt man wiederum eine Zeichenfolge, die nicht in der Bezeichnung der Kampagne zu finden sein soll. In der dritten und vierten Spalte kann dies ebenfalls für die Anzeigengruppen hinterlegt werden. Pro Spalte kann auch ein Zweiter Wert in jede Zelle eingetragen werden. Die beiden Werte müssen dabei durch ein Komma getrennt werden. Das Komma wird dann in der späteren Abfrage wie ein Oder behandelt. In den restlichen Spalten definiert man die Werte, mit denen die Snippet-Erweiterungen befüllt werden sollen. Hier können maximal 5 Werte hinterlegt werden. Von welchem Typ diese sein sollen, kann im Programmcode des Skriptes eingestellt werden. Falls eine dieser Bedingungen einmal nicht benötigt wird, kann die nicht benötigte Zelle einfach leer gelassen werden. In folgendem Beispiel werden also die Marken Adidas, Puma und Geox zu allen Anzeigengruppen, die im Anzeigengruppennamen die Zeichenfolge „Sneaker“ aber nicht „Schwarz“ oder „Rot“ enthalten und sich in einer Kampagne befinden, die die Zeichenfolge „Schuhe“ oder „Generisch“ aber nicht „Brand“ enthält, hinzugefügt.

Das Skript labelt bei jedem Durchlauf die Elemente, in denen es eine Snippet-Erweiterung eingefügt hat. Somit merkt es sich, wo bereits Änderungen vorgenommen wurden und ignoriert diese beim nächsten Durchlauf. Dies verbessert die Laufzeit des Skriptes und es entstehen keine unnötigen Fehlermeldungen.

/********************
Title: Snippet Builder
Author: Sebastian Zehelein
Lastest Version: 1.2
Last Update: 29.01.2018

Change-Log:
  1.0  Release
  1.1   - Ability to create snippets on campaign level
        - Ability to define which type of snippet should be created
        - Ability to define detail level of protocoll
  1.2  Runtime optimization with labels
*********************/

//Defines on which level the snippets should be created (adgroup | campaign)
var level = "adgroup";

//Defines which type of snippet should be created
//For possible Values visit https://developers.google.com/adwords/api/docs/appendix/structured-snippet-headers
var type = "Brands";

//Defines after how many created snippets a message should be written into the log
var detailLog = 1;

//Link to the config spreadsheet
var spreadsheetURL = "https://docs.google.com/spreadsheets/d/1g5iYO_2DspilWw0fx4g10WOOYHsEdO5_NTX9UcQFNeQ/edit#gid=0";

function main() {
  var i3 = 1;
  var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetURL).getActiveSheet();
  
  //Goes through the spreadsheet and reads the config 
  for (var i = 2; i <= spreadsheet.getLastRow(); i++) {
    var campaignPositives = spreadsheet.getRange("A" + i).getValue();
    if (campaignPositives != '') {
      if (level == "adgroup") {
    	campaignPositives = "CampaignName CONTAINS '" + 
      	campaignPositives.substring(0, campaignPositives.indexOf(",")) + 
      	campaignPositives.substring(campaignPositives.indexOf(","), campaignPositives.length).split(",").join("' AND CampaignName CONTAINS '") + "'";
      } else {
        campaignPositives = "Name CONTAINS '" + 
      	campaignPositives.substring(0, campaignPositives.indexOf(",")) + 
      	campaignPositives.substring(campaignPositives.indexOf(","), campaignPositives.length).split(",").join("' AND Name CONTAINS '") + "'";
      } 
    } else {
      campaignPositives = "";
    }
     
    var campaignNegatives = spreadsheet.getRange("B" + i).getValue();
    if (campaignNegatives != '') {
      if (level == "adgroup") {
        campaignNegatives = "CampaignName DOES_NOT_CONTAIN '" + 
        campaignNegatives.substring(0, campaignNegatives.indexOf(",")) + 
        campaignNegatives.substring(campaignNegatives.indexOf(","), campaignNegatives.length).split(",").join("' AND CampaignName DOES_NOT_CONTAIN '") + "'";
      } else {
        campaignNegatives = "Name DOES_NOT_CONTAIN '" + 
      	campaignNegatives.substring(0, campaignNegatives.indexOf(",")) + 
      	campaignNegatives.substring(campaignNegatives.indexOf(","), campaignNegatives.length).split(",").join("' AND Name DOES_NOT_CONTAIN '") + "'";
      }
    } else {
      campaignNegatives = "Name CONTAINS ''";
    }
    
  	var adGroupPositives = spreadsheet.getRange("C" + i).getValue();
    if (adGroupPositives != '') {
    	adGroupPositives = "Name CONTAINS '" + 
    	adGroupPositives.substring(0, adGroupPositives.indexOf(",")) + 
    	adGroupPositives.substring(adGroupPositives.indexOf(","), adGroupPositives.length).split(",").join("' AND Name CONTAINS '") + "'";
    } else {
      	adGroupPositives = "";
    }
    
    var adGroupNegatives = spreadsheet.getRange("D" + i).getValue();
    if (adGroupNegatives != '') {
    	adGroupNegatives = "Name DOES_NOT_CONTAIN '" + 
      	adGroupNegatives.substring(0, adGroupNegatives.indexOf(",")) + 
      	adGroupNegatives.substring(adGroupNegatives.indexOf(","), adGroupNegatives.length).split(",").join("' AND Name DOES_NOT_CONTAIN '") + "'";
    } else {
      	adGroupNegatives = "Name CONTAINS ''";
    }
    
    var values = new Array();
      
    for (var i2 = 5; i2 <= 9; i2++) {
      if (spreadsheet.getRange(i, i2).getValue() != '') {
      	values.push(spreadsheet.getRange(i, i2).getValue());
      } else {
        break;
      }
    }
    
    //Creates the snippet extensions
    var snippet = AdWordsApp.extensions().newSnippetBuilder().withHeader(type).withValues(values).build().getResult();
    
    if (level == "adgroup") {
      try {
        var adGroups = AdWordsApp.adGroups()
        .withCondition(campaignPositives)
        .withCondition(campaignNegatives)
        .withCondition(adGroupPositives)
        .withCondition("LabelNames CONTAINS_NONE ['Snippet Builder']")
        .withCondition(adGroupNegatives).get();
      } catch (e) {
        var adGroups = AdWordsApp.adGroups()
        .withCondition(campaignPositives)
        .withCondition(campaignNegatives)
        .withCondition(adGroupPositives)
        .withCondition(adGroupNegatives).get();
      }
    
  
	  while (adGroups.hasNext()) {
      	var adGroup = adGroups.next();
        
        if (!adGroup.extensions().snippets().get().hasNext()) {
          try {
            adGroup.applyLabel("Snippet Builder");
          } catch (e) {
            createLabel();
            adGroup.applyLabel("Snippet Builder");
          }
          adGroup.addSnippet(snippet);
          (i3 % detailLog == 0) ? Logger.log(i3 + " " + adGroup.getName() + ": " + snippet.getHeader() + " => " + snippet.getValues()) : "";
          i3++;
        }
      }
    }
    
    if (level == "campaign") {
      try {
        Logger.log(campaignPositives);
        Logger.log(campaignNegatives);
        var campaigns = AdWordsApp.campaigns()
        .withCondition(campaignPositives)
        .withCondition("LabelNames CONTAINS_NONE ['Snippet Builder']")
        .withCondition(campaignNegatives).get(); 
      } catch (e) {
        var campaigns = AdWordsApp.campaigns()
        .withCondition(campaignPositives)
        .withCondition(campaignNegatives).get(); 
      }
  
	  while (campaigns.hasNext()) {
      	var campaign = campaigns.next();
        
        if (!campaign.extensions().snippets().get().hasNext()) {
          try {
          	campaign.applyLabel("Snippet Builder");
          } catch (e) {
            createLabel();
            campaign.applyLabel("Snippet Builder");
          }
          campaign.addSnippet(snippet);
          (i3 % detailLog == 0) ? Logger.log(i3 + " " + campaign.getName() + ": " + snippet.getHeader() + " => " + snippet.getValues()) : "";
          i3++;
        }
      }
    }
  }
}

function createLabel() {
  Logger.log("No Label found in the account. Creating new one.");
  AdWordsApp.createLabel('Snippet Builder', 'Label for the Snippet Creator Script', '#559096');
}
Sebastian Zehelein
Ehem. Senior Online Marketing Manager

Sebastian war bis 2022 Senior Online Marketing Manager bei The Boutique Agency.