Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Script for adding YT-channels to exclusion list

28 views
Skip to first unread message

Jakob Wik Kaad Knudsen

unread,
Feb 3, 2025, 8:51:32 AMFeb 3
to Google Ads Scripts Forum
Hi!

I'm trying to create a script that excludes YouTube-channels based on a list of characters I don't want to be targeting.

I don't know much about coding nor creating scripts, so I'm using ChatGPT to do it, as I haven't found a script that does it like I want it to. 

This is the script I created so far:
var config = {
  LOG: true,
  EXCLUSIONS_LIST: "DK - Masimo negative YouTube channels", // 🎯 Exclusion list at the account level
  IMPRESSION_THRESHOLD: 0, // Minimum number of impressions before exclusion
  DAYS_TO_CHECK: 30, // Scans YouTube placements from the last 30 days
  EXCLUDE_TERMS: [ // 🎯 Unwanted characters or words in the placement name
    "Ç", "گ", "و", "د", "ا", "ل", "ك", "ت", "ب", "ل", "ه",
    "в", "Д", "д", "ь", "ق", "ر", "آ", "ن", "ن", "و", "ر", "ه", "ي", "ة",
    "ж", "б", "ч", ".xyz", ".pl", "spil", "spill", "spel", "spiel", "plays",
    ".store", ".site", ".space", ".gg", "game", "kids", "congo", "poki",
    "柴", "犬", "春", "卷", "的", "英", "國", "日", "常"
  ]
};

function main() {
  var excludedChannelIds = [];

  // Calculate date range
  var today = new Date();
  var startDate = new Date(today.getTime() - (config.DAYS_TO_CHECK * 24 * 60 * 60 * 1000));
  var formattedToday = Utilities.formatDate(today, AdsApp.currentAccount().getTimeZone(), "yyyyMMdd");
  var formattedStartDate = Utilities.formatDate(startDate, AdsApp.currentAccount().getTimeZone(), "yyyyMMdd");

  Logger.log("🔍 Scanning YouTube placements from: " + formattedStartDate + " to " + formattedToday);

  // ✅ SQL query: Matches **PLACEMENT NAME** from Google Ads interface
  var query = "SELECT group_placement_view.target_url, group_placement_view.display_name " +
              "FROM group_placement_view " +
              "WHERE group_placement_view.placement_type = 'YOUTUBE_CHANNEL' " +
              "AND metrics.impressions > " + config.IMPRESSION_THRESHOLD + " " +
              "AND segments.date BETWEEN '" + formattedStartDate + "' AND '" + formattedToday + "'";

  var report = AdsApp.report(query);
  var rows = report.rows();

  if (!rows.hasNext()) {
    Logger.log("⚠️ No YouTube placements found in the period.");
    return;
  }

  while (rows.hasNext()) {
    var row = rows.next();
    var placementUrl = row['group_placement_view.target_url']; // YouTube channel URL
    var placementDisplayName = row['group_placement_view.display_name']; // 🎯 Placement name from UI

    if (!placementDisplayName) {
      Logger.log("⚠️ Ignoring placement without a name.");
      continue; // Ignore placements without a name
    }

    placementDisplayName = placementDisplayName.toString().trim(); // Ensure correct format

    Logger.log("🔍 Reviewing placement: " + placementDisplayName + " (" + placementUrl + ")");

    if (shouldExcludePlacement(placementDisplayName)) {
      var channelId = extractYouTubeChannelId(placementUrl);
      if (channelId) {
        excludedChannelIds.push(channelId);
        Logger.log("❌ **Marked for exclusion**: " + placementDisplayName + " -> " + channelId);
      } else {
        Logger.log("⚠️ Could not extract YouTube channel ID from: " + placementUrl);
      }
    }
  }

  // ➕ Add excluded placements to the exclusion list
  if (excludedChannelIds.length > 0) {
    var exclusionList = getOrCreatePlacementExclusionList(config.EXCLUSIONS_LIST);
    addPlacementsToExclusionList(exclusionList, excludedChannelIds);
  } else {
    Logger.log("✅ **No placements matched the exclusion criteria.**");
  }
}

// 🔍 Check if the placement name contains **one or more** unwanted characters
function shouldExcludePlacement(name) {
  for (var i = 0; i < config.EXCLUDE_TERMS.length; i++) {
    if (name.includes(config.EXCLUDE_TERMS[i])) {
      Logger.log("⚠️ Found unwanted character '" + config.EXCLUDE_TERMS[i] + "' in placement name: " + name);
      return true;
    }
  }
  return false;
}

// 📌 Extract YouTube channel ID from URL
function extractYouTubeChannelId(url) {
  var match = url.match(/youtube\.com\/channel\/([a-zA-Z0-9_-]+)/);
  return match ? match[1] : null;
}

// 🔧 Retrieve or create an exclusion list at the account level
function getOrCreatePlacementExclusionList(listName) {
  var lists = AdsApp.excludedPlacementLists().withCondition("Name = '" + listName + "'").get();
 
  if (lists.hasNext()) {
    Logger.log("✅ Exclusion list found: " + listName);
    return lists.next();
  } else {
    Logger.log("🆕 Creating new exclusion list: " + listName);
    return AdsApp.newExcludedPlacementListBuilder().withName(listName).build();
  }
}

// ➕ **Correctly add placements to the exclusion list**
function addPlacementsToExclusionList(exclusionList, channelIds) {
  if (channelIds.length === 0) {
    Logger.log("❌ No valid YouTube channel IDs found.");
    return;
  }

  try {
    exclusionList.addExcludedYouTubeChannels(channelIds);
    Logger.log("✅ Added " + channelIds.length + " YouTube channels to the exclusion list.");
  } catch (e) {
    Logger.log("❌ Error while adding: " + e.message);
  }
}


The script I made up until now is doing what I ask it to do (finding YT-channels where the channel name include one of my unwanted chraracters e.g.: 能). After finding the channel it is then supposed to add the channel to an exclusion list by sending the Channel ID or the URL to the exclusion list, but here it does nothing, as you can see below:
Skærmbillede 2025-02-03 125704.png

There are also none actions in the changes column as you can see:
Skærmbillede 2025-02-03 134151.png
Therefore ChatGPT asked me to run a test to see if I could add a YouTube placement to the exclusion list via script, at all. 

Thus it made an example of a script where we should test if the ability to add negative YT-accounts to an exclusion list was possible at all. We're doing so by giving the script one specific YT-channel to exclude (UCkD0NX-oq1BOQ7cxl7VDQww)

This is the test script:
function main() {
  testExclusion();
}

function testExclusion() {
  var listName = "DK - Masimo negative YouTube channels";
  var testChannelId = "UCkD0NX-oq1BOQ7cxl7VDQww"; // Dummy test channel ID
  var testChannelUrl = "https://www.youtube.com/channel/" + testChannelId; // Correct format for YouTube channels

  Logger.log("🔍 Testing manual addition of channel ID: " + testChannelId);

  var lists = AdsApp.excludedPlacementLists()
    .withCondition("Name = '" + listName + "'")
    .get();
 
  if (!lists.hasNext()) {
    Logger.log("❌ The exclusion list '" + listName + "' was not found!");
    return;
  }

  var exclusionList = lists.next();
  Logger.log("✅ Exclusion list found: " + listName);

  try {
    // Correctly adds the placement to the exclusion list
    exclusionList.addExcludedPlacements([testChannelUrl]);
    Logger.log("✅ Test channel successfully attempted to be added to the exclusion list: " + testChannelUrl);
  } catch (e) {
    Logger.log("❌ Error while adding: " + e.message);
  }
}

Here the script is actually trying to add the placement but I get this error code under the column 'Changes':
Skærmbillede 2025-02-03 134523.png

I feel like I'm really close but I just don't know how til fix this issue with actually adding the specific YT-URL or YT-channel to the Account exclusion list.. Is it possible at all, or do I need to get the script to make the changes directly in the campaigns?Can you help me to spot where it goes wrong? 

Best regards,
Jakob.

Google Ads Scripts Forum

unread,
Feb 3, 2025, 5:28:43 PMFeb 3
to Google Ads Scripts Forum

Hi Jakob,

Thank you for reaching out to the Google Ads Scripts support team.

Please be informed that our team will not be able to provide support for third party scripts. I would like to inform you that the method “AdsApp.excludedPlacementLists()” you are using will be related to the search and display campaigns. This method won’t work for youtube videos as it will be suitable for search and display campaigns. For YouTube videos, I would suggest that you use video placement exclusion by referring to the “AdsApp.​ExcludedVideoPlacementSelector” document and exclude the unwanted placements.

Additionally, I would recommend that you refer to the AdsApp.​ExcludedVideoYouTubeChannel, AdsApp.​ExcludedVideoYouTubeChannelSelector, and AdsApp.​VideoTargeting for more information.

I hope this helps! Kindly get back to us if you still have any concerns.


Thanks,
Google Ads Scripts support team
Reply all
Reply to author
Forward
0 new messages