Display Automatisch Uitsluiten

Verbeter de kwaliteit van Display plaatsingen door automatisch plaatsingen uit te sluiten op basis van woorden.

Start nu!
Display Automatisch Uitsluiten
Display Get started!

Het Google Display Netwerk staat doorgaans niet bekend om zijn kwalitatieve plaatsingen. Regelmatig vind je irrelevante en buitenlandse websites tussen je Display plaatsingen waar je niet op wil targeten. Dit script geeft je meer grip op de kwaliteit van de plaatsingen door plaatsingen zo snel mogelijk uit te sluiten op basis van je criteria. Dit wordt op twee manieren gedaan:

  1. Alle plaatsingen uitsluiten die woorden bevatten die je aan het script hebt toegevoegd. Als je bijvoorbeeld niet wil targeten op websites die 'viral' bevatten kan je deze aan de array excludeDomains toevoegen en zal worden uitgesloten elke keer als het script draait.
  2. Behoudt alleen plaatsingen die bepaalde woord-delen bevatten. Als je bijvoorbeeld alleen plaatsingen wil die '.nl' bevatten, voeg je deze toe aan mustInclude op dezelfde manier als de huidige woorden. Alle niet .nl domeinen zullen elke keer als het script draait worden uitgesloten.
  3. Nieuw: voeg uitzonderingen toe aan de exceptions array. Wanneer je geen uitzonderingen hebt vul een lege array in: []
  4. Nieuw: nu ook YouTube uitsluitingen mogelijk
The script
/**
 * @name Placement Excluder YouTube & Display
 *
 * @instructions
 *     - ⚠ Enable "New scripts experience" above google ads script ⚠
 *     - Find settings in the config variable
 *     
 * @notes
 *     - Check log files below for execution information.
 *     - Run a preview before first usage.
 *
 * @version 2.10
 *
 * @author Bas Baudoin - adsscripts.com
 *
 */

const config = {
  modus: 'list', // add 'campaign', or 'list',
  listName: 'script_display', // when in list modus, e.g. 'exclusions list' (should already exist)
  excludeDomain: true, // by default it only excludes URLs, but it can also exclude the domain
  excludeUrl: false, // exclude full url
  type: 'youtube', // 'display' or 'youtube'
  lastXdays: 1, // 0 = today, 1 = today+yesterday, etc.

  excludeDomains: ['20min.ch', '.tk', '.ru', 'viral', '.za', '.ru'], // example: ['20min.ch', '.tk', '.de', 'viral'],
  mustInclude: ['.nl', '.com', '.nu', '.net'],
  exceptions: ['zaaltje'],

  // for developer
  testMode: false, // = false for normal operation
  reverse: false, // = false for normal operation
}

function main() {
  console.log('starting script...')
  const { excludeDomains, mustIncludes } = createRegexes()
  //console.log(excludeDomains)
  const startDate = getDateByDaysAgo(config.lastXdays)
  const endDate = getDateByDaysAgo(0)
  console.log(startDate, endDate)
  const rev = config.reverse && config.testMode ? 'NOT ' : ''

  let qBase = "SELECT detail_placement_view.target_url, detail_placement_view.placement_type, detail_placement_view.placement, detail_placement_view.group_placement_target_url, detail_placement_view.display_name, metrics.ctr, ad_group.name, campaign.id, campaign.name, metrics.impressions, metrics.clicks, metrics.conversions, metrics.ctr "
  qBase += 'FROM detail_placement_view '
  qBase += `WHERE segments.date BETWEEN '${startDate}' AND '${endDate}' `
  //console.log(qBase)

  console.log('Excluding 🔂 terms and domains')
  const qDomains = qBase + `AND detail_placement_view.target_url ${rev}REGEXP_MATCH '${excludeDomains}' `
  if (config.excludeDomains.length > 0) excludeLoop(qDomains)

  console.log('Excluding 🔂 "must contain"')
  const qPerformance = qBase + `AND detail_placement_view.target_url NOT REGEXP_MATCH '${mustIncludes}' `
  excludeLoop(qPerformance)
}

// --- //

function excludeLoop(q) {
  var report = AdsApp.report(q)

  let list
  if (config.listName !== '') {
    list = AdsApp.excludedPlacementLists().withCondition('Name = "' + config.listName + '"').get().next()
  }

  let exclusions = []
  const accountName = AdsApp.currentAccount().getName()
  const startDate = getDateByDaysAgo(config.lastXdays)
  const endDate = getDateByDaysAgo(0)
  const dateRange = `${startDate} - ${endDate}`

  const rows = report.rows()
  
  while (rows.hasNext()) {
    const row = rows.next()
    console.log('---')
    const placementUrl = row['detail_placement_view.target_url']
    const campaignId = row['campaign.id']
    const campaignName = row['campaign.name']
    const impressions = row['metrics.impressions']
    const clicks = row['metrics.clicks']
    const conversions = row['metrics.conversions']
    console.log('🛑 excluding', placementUrl, campaignName)

    // check if in exclusion list
    const isInExceptionList = config.exceptions.find(x => {
      if (placementUrl) {
        return placementUrl.includes(x)
      }
    })
    if (isInExceptionList) {
      console.log(`Placement excluded because it is in exclusion list: ${isInExceptionList} in ${placementUrl}`)
      continue
    }

    if (config.modus === 'campaign') {
      if (config.excludeUrl) {
        excludePlacementInCampaign(placementUrl, campaignId)
      }
      
      if (config.excludeDomain) {
        const domain = placementUrl.split('/')[0]
        if (domain.includes('.')) {
          excludePlacementInCampaign(domain, campaignId)
        }
      }
    }
    
    if (config.modus === 'list') {
      if (config.excludeUrl) {
        list.addExcludedPlacement(placementUrl)
      }
      
      if (config.excludeDomain) {
        const domain = placementUrl.split('/')[0]
        if (domain.includes('.')) {
          list.addExcludedPlacement(domain)
        }
      }
    }
    
    exclusions.push([accountName, dateRange, placementUrl, campaignName, impressions, clicks, conversions]) // not used
  }
}

function createRegexes() {
  const excludeDomains = '(^.*' + config.excludeDomains
    .map(x => x.replace(/\./g, '[.]'))
    .join('.*$)|(^.*') + '.*$)'
  const mustIncludes = '(^.*' + config.mustInclude
    .map(x => x.replace(/\./g, '[.]'))
    .join('.*$)|(^.*') + '.*$)'
  return { excludeDomains, mustIncludes }
}

function excludePlacementInCampaign(placementUrl, campaignId) {
  let campaigns
  
  if (config.type === 'youtube') {
    console.log('❗❗ cannot exclude placements in youtube campaigns via scripts, use list mode')
    // hope that google will allow this in the future (2022-07-26)
    return
  }
  
  if (config.type === 'display') {
    campaigns = AdsApp.campaigns().withIds([parseInt(campaignId)]).get()
    if (campaigns.totalNumEntities() != 1) {
      console.log('⚠ campaign Id not found ' + campaignId)
      return
    }
  }
    
  const campaign = campaigns.next()
  const res = campaign.display().newPlacementBuilder().withUrl(placementUrl).exclude()
}

function getDateByDaysAgo(daysAgo) {
  let today = new Date()
  today.setDate(today.getDate() - daysAgo)
  var formattedDate = Utilities.formatDate(today, 'PST', 'yyyy-MM-dd')
  return formattedDate
}
Show whole script!
Loading Comments
The Experts
Tibbe van Asten Team Lead Performance Marketing
Nils Rooijmans Water Cooler Topics
Martijn Kraan Freelance PPC Specialist
Bas Baudoin Teamlead SEA @ Happy Leads
Jermaya Leijen Digital Marketing Strategist
Krzysztof Bycina PPC Specialist from Poland
How about you? JOIN US!
Sharing Knowledge
Caring

Adsscripts.com staat voor het delen van kennis. In de huidige markt houden SEA-specialisten de kennis en ervaring graag voor zich. Wij zijn er van overtuigd dat het delen van kennis ervoor kan zorgen dat iedereen beter wordt in haar of zijn werk. Daarom lopen wij hier graag in voorop, door onze kennis over scripts te delen met iedereen.

Wil jij ook graag een bijdrage leveren? Wij staan open voor nieuwe ideeën en feedback op alles wat je op Adsscripts.com vindt.

Neem contact op

Training &
Workshop
Neem contact op!
Adsscripts Training & Workshop