Issue creating labels for accounts in MCC?

121 views
Skip to first unread message

Christopher Larkin

unread,
Sep 7, 2019, 10:54:17 PM9/7/19
to Google Ads Scripts Forum
I'm using the following code to add labels to accounts under our MCC. 

The intention was to use these labels *inside* those accounts. Am I approaching this wrong? 

Goal:
  1. Programmatically create labels for future use (selection) inside these client accounts
  2. Saving time by creating in advance and preventing typos by having the code add these labels
// MCC Campaign Initializer v1.2 by Chris Larkin for Arcalea

// This script initializes campaigns that have been added to the MCC but do not have some of the
// default features that Arcalea uses, like the ad testing labels.

var labels = []; // contains labels for accounts

function main() {
var i = 0; // loop label name
var CID = '419-034-2179';

// Setup labels
labels.push("Paused 1/4");
labels.push("Paused 1/3");
labels.push("Paused 1/2");
labels.push("Paused 2/3");
labels.push("Paused 3/4");
labels.push("Paused 100%");
Logger.log('%s labels in label array', labels.length);
getAllAccounts();
for(i=0; i < accounts.length; i++) {
createAllLabels(accounts[i].account);
}
}

function createAccountLabels(_labelToMake) {
var labelName = _labelToMake;
AdsManagerApp.createAccountLabel(labelName);
Logger.log("Label with text = '%s' created.", labelName);
}

function createAllLabels(_account){
var i = 0; // loop label names
var account = _account;
AdsManagerApp.select(account);

for(i=0; i < labels.length; i++) {
createAccountLabels(labels[i]);
}
}
/**
*
* @param {boolean} _includeDisabled is true for all accounts, false for accounts with impressions only
*/
function getAllAccounts(_includeDisabled) {
var includeDisabled;
var numberOfAccounts = 0;

// default value handlers
_includeDisabled = typeof _includeDisabled !== 'undefined' ? _includeDisabled : false;
if (_includeDisabled) {
includeDisabled = "Impressions >= 0";
} else {
includeDisabled = "Impressions > 0";
}
var accountSelector = AdsManagerApp
.accounts()
.withCondition(includeDisabled)
.forDateRange("THIS_MONTH")
.orderBy("Clicks DESC");

var accountIterator = accountSelector.get();
while (accountIterator.hasNext()) {
var account = accountIterator.next();
var accountName = account.getName() ? account.getName() : '--';
Logger.log('%s,%s,%s,%s', account.getCustomerId(), accountName,
account.getTimeZone(), account.getCurrencyCode());
numberOfAccounts ++;
if (accountName !== 'Lumiere Child -MC') {
accounts.push(
{ account: account,
name: account.accountName,
CID: account.getCustomerId(),
timeZone: account.getTimeZone(),
currencyCode: account.getCurrencyCode()
});
} }
Logger.log('%s accounts found in query', numberOfAccounts);
}

Google Ads Scripts Forum Advisor Prod

unread,
Sep 8, 2019, 11:19:47 PM9/8/19
to adwords...@googlegroups.com
Hi Christoph,

Thanks for sharing your concern and hope you are fine.

Upon trying the provided code on my test account, I noticed that this script is encountering the "ReferenceError: "accounts" is not defined.". The reason for this error is that the variable 'accounts' that you've in the line 71 of your code is not declared yet. With this, you may try to declare the variable first inside the function getAllAccounts(_includeDisabled).

After implementing the above suggestion, the script will encounter this error "ReferenceError: "accounts" is not defined.". To resolve this error you need to move the below iteration to the function getAllAccounts(_includeDisabled) from the function main().

    for(i=0; i < accounts.length; i++) {
        createAllLabels(accounts[i].account);
    }

After applying the suggestions, the code will be looked like the script below.
// MCC Campaign Initializer v1.2 by Chris Larkin for Arcalea

// This script initializes campaigns that have been added to the MCC but do not have some of the 
// default features that Arcalea uses, like the ad testing labels. 

var labels = [];    // contains labels for accounts

function main() {
    
    var i = 0;          // loop label name
 
    //var CID = '419-034-2179'; 


    // Setup labels
    labels.push("Paused 1/4");
    labels.push("Paused 1/3");
    labels.push("Paused 1/2");
    labels.push("Paused 2/3");
    labels.push("Paused 3/4");
    labels.push("Paused 100%");
    Logger.log('%s labels in label array', labels.length);
    getAllAccounts();
}

function createAccountLabels(_labelToMake) {
  var labelName = _labelToMake;
  AdsManagerApp.createAccountLabel(labelName);
  Logger.log("Label with text = '%s' created.", labelName);
  }

  function createAllLabels(_account){
        var i = 0;          // loop label names
        var account = _account;
        AdsManagerApp.select(account);

        for(i=0; i < labels.length; i++) {
            createAccountLabels(labels[i]);
        }
  }
/**
 * 
 * @param {boolean} _includeDisabled is true for all accounts, false for accounts with impressions only
 */
  function getAllAccounts(_includeDisabled) {
    var includeDisabled;
    var numberOfAccounts = 0;
    var accounts = [];
    for(i=0; i < accounts.length; i++) {
        createAllLabels(accounts[i].account);
    }
  }


Let me know if you have further questions/clarifications.

Regards,
Ejay
Google Ads Scripts Team

ref:_00D1U1174p._5001UHG4ME:ref

Christopher Larkin

unread,
Sep 8, 2019, 11:27:02 PM9/8/19
to Google Ads Scripts Forum
Sorry, I failed to mention that I place all of my repeated functions into a separate file that I load into a separate .gs at the script level as shown in the attached image.

MCC Library 2.4 gs Screenshot at Sep 08 22-24-07.png


When I preview this script in GAds, it works fine, even showing the changes I expect where I expect them; however, when I run the script, I get the message "An error occurred. Please try again later." for each of the label additions. 

Any thoughts? Should I post all my code? Does the separate .gs script work differently from how I understand it? 

Thanks again for your help Ejay -
Christopher 



// MCC_Library.js v2.4 2019-09-07
// Written by Chris Larkin for Arcalea, where Success Is Now A Science


// This library contains all of the functions that are used in our MCC-related scripts.

// With the August 30, 2019 release of MCC_Library.js, functions like the email logger, 
// spend checker, and campaign pause are contained in this reusable library that applies  
// to all Google Ads scripts we develop. This update is intended to reduce development time
// and improve documentation.

// When implementing in Google Ads, if using any of the reusable functions, simply load
// this script into Google Ads as "MCC_Library.gs" and call the functions from the main 
// program as though these functions were a part of the same file.

// Google Ads treats all scripts as though they were in a single file, and separating 
// Code.gs and MCC_Library.gs is just a convenient way to reuse the same codebase over
// and over.

// Notes: each function has definition information as specified in Jsdoc ->
// https://devhints.io/jsdoc <- as well as the version number, original source script
// and any information necessary to develop using that function.

// Global variables

// Evening start and morning stop date/time variables
var eveningStartDate = new Date('May 26, 2019 14:00:00 -0500'); // use -0500 in order to compare against Central Time
var morningEndDate = new Date('May 31, 2019 14:05:00 -0500'); 

var dayOfMonth = getDayOfMonth();

// Email settings
var lineFeed = "\n";
var eMail = "";

var messageToSend = false; // change to true to force an email notification
var emailTo = 'ch...@arcalea.com';
var emailSubject;
var emailStart = 'This message contains details about an automated script in Google Ads.' + lineFeed + lineFeed;
var separator = '----------------------------------------';

// Account and campaign variables

var account;
var accounts = [];
var campaign;
var campaigns = [];

function callback(passedValue){
    // This function is called as part of the executeInParallel command, in the main() of a project's primary 
    // .gs file. 

    // The line of code below is an example of the function that calls this function in the first place
    // MccApp.accounts().withIds(ids).withLimit(50).executeInParallel('runRows','callBack',JSON.stringify(SETTINGS));

}


// function buildNameCondition
/**
 * 
 * @param {string} nameText The name of a given object like campaign or label, to be changed into a withConditions 
 * @return {string} Returns text for withConditions CONTAINS match 
 */

function buildNameCondition(nameText) {
    var nameCondition = "Name CONTAINS '" + nameText + "'";
    return nameCondition;
}
// function buildNameCondition end

// function checkSpend start
/**
 * Checks the spend of a given account's campaign or campaigns against a limit for a specific date range.
 *
 * @param {string} thisCampaign Part or all of a campaign name to match. 
 * @param {number} budgetLimit Maximum allowable spend for period.
 * @param {date} fromDate A date object. Start of range to check.
 * @param {date} toDate A date object. End of range to check.
 * @param {string} matchType Either Exact or Contains, used to set the withConditions name match type.
 * @param {string} CID MCC version: required to specify the account to check campaigns under.
 * @return {boolean} False if the CID is not provided.
 */
function checkSpend(thisCampaign, budgetLimit, fromDate, toDate, matchType, CID) {
    // checkSpend 20190831.001
    // imported from CH-FS 2019-09-02 End Date MCC.js
    
    // default value handlers
    matchType = typeof matchType !== 'undefined' ? matchType : 'Exact';

    if (typeof CID == 'undefined') {
        Logger.log('checkSpend called with ' + thisCampaign + ' and no CID');
        return false;
    }

    // Account selector and iterator uses the (faster) ID matching - this is the preferred GAds
    // script selector method for performance reasons. 

    var accountSelector = AdsManagerApp
        .accounts()
        .withIds([CID]);

    var accountIterator = accountSelector.get();

    while (accountIterator.hasNext()) {
        var thisAccount = accountIterator.next();
        // Logger.log(thisAccount.getName());
    }

    MccApp.select(thisAccount);

    // Variables
    var nameCondition; // string for selector
    var totalSpent = 0; // total for campaigns checked

    switch (matchType) {
        case 'Exact':
            nameCondition = 'Name = ' + '"' + thisCampaign + '"';
            break;
        case 'Contains':
            nameCondition = 'Name CONTAINS_IGNORE_CASE ' + '"' + thisCampaign + '"';
            break;
        default:
            nameCondition = "ERROR";
    }
    // var nameCondition = 'Name = '+'"'+thisCampaign+'"';
    // Logger.log("Name condition string is " + nameCondition);

    // Iterator
    var campaignIterator = AdsApp.campaigns()
        .withCondition(nameCondition)
        // .withCondition("Status = ENABLED")
        .get();
    while (campaignIterator.hasNext()) {
        var campaign = campaignIterator.next();
        var stats = campaign.getStatsFor(fromDate, toDate);
        var campaignCost = stats.getCost();
        totalSpent += campaignCost;
        var campaignName = campaign.getName();
        //  Logger.log("  Cost for "+ campaignName + " from "+fromDate + " to "+toDate+ " is " +campaignCost);
    }
    if (totalSpent >= budgetLimit) {
        Logger.log("  Due to spend - pausing " + thisCampaign + ' with total spend $' + totalSpent + ' against $' + budgetLimit + ' limit.');
        pauseCampaignByName(thisCampaign, matchType);
    }
    Logger.log("    " + thisCampaign + ' with total spend $' + totalSpent + ' against $' + budgetLimit + ' limit.');
}
// function checkSpend end

function getDayOfMonth() {
    var thisDate = new Date();
var thisDayofMonth = thisDate.getDate();
    Logger.log(thisDayofMonth);
    return thisDayofMonth;
}


// function labelChecker start
/**
 * Checks for the existence of a label on an account
 *
 * @param {string} labelText Function checks existence of this Label.
 * @return {boolean} True if the Label is present.
 */
function labelChecker(labelText) {
    if (typeof labelText == 'undefined') {
        Logger.log('labelChecker called with no labelText');
        return false;
    }
    var labelSelector = AdsApp.labels()
        .withCondition("CampaignsCount > 5")
        .orderBy("CampaignsCount DESC");

    var labelIterator = labelSelector.get();
    while (labelIterator.hasNext()) {
        var label = labelIterator.next();
    }    
}
// function labelChecker end


// function labelCreator start
/**
 * Creates a label for an account
 *
 * @param {string} labelText Function checks existence of this Label.
 * @return {boolean} True if the Label is present.
 */
function labelCreator(labelText) {
    if (typeof labelText == 'undefined') {
        Logger.log('labelCreator called with no labelText');
        return false;
    }
    if (labelChecker(labelText)) {
        return true
    }
    // code below creates the label in Google Ads

}
// function labelCreator end


/**
 * xMsg is a wrapper for text to be added to email notifications, or to log to the screen.
 *
 * @param {string} messageText Content of message to process/display
 * @param {boolean} onScreen Display message in log on screen? Defaults to true.
 * @param {boolean} addLinefeed Append linefeed to message? Defaults to true.
 * @return {string} Returns the original or post-processed message text.
 */
function xMsg(messageText, onScreen, addLinefeed) {
    // xMsg v20190814.001
    
    // default value handlers
    onScreen = typeof onScreen !== 'undefined' ? onScreen : true;
    addLinefeed = typeof addLinefeed !== 'undefined' ? addLinefeed : true;
if (addLinefeed) {
        messageText += lineFeed;
    }

    if (onScreen) {
        Logger.log(messageText);
    }
    return messageText;
}

Google Ads Scripts Forum Advisor Prod

unread,
Sep 9, 2019, 12:59:12 AM9/9/19
to adwords...@googlegroups.com
Hi Christopher,

So that I can take a closer look, could you provide the customer ID and the name of the script via Reply privately to author option where you encountered the issue?
Message has been deleted

Google Ads Scripts Forum Advisor

unread,
Sep 10, 2019, 10:11:41 PM9/10/19
to adwords...@googlegroups.com
Hi Christopher,

Thanks for the followup.

It appears that you did not receive my private response as the provided suggestion is not implemented yet.

Let me explain first the 2 levels of Google Ads label. The Google Ads scripts allow you to create labels within manager accounts, as well as apply labels to Google Ads accounts under that manager account. The other level of label is within the account where you can use to campaigns, ad groups, ads, and keywords.

Moving forward to your concern, since you want to create a label to use in your campaigns, ad groups, ads, and keywords, instead of using the AdsManagerApp.createAccountLabel() (line 30 of 'MCC Campaign Initializer v1.2'), you need to replace it with AdsApp.createLabel(). I tried to use the script on my test account by applying my suggestion and the script worked as expected. I did not encountered any issues also.

With this, please try to implement the provided suggestion and if the issues persists, let me know.
Reply all
Reply to author
Forward
0 new messages