Redirect Ad Updater

Save time by automatically update your ads' final URL redirects.

Start Now!
Redirect Ad Updater
Redirect Get started!

Website change, landing pages change and URLs change. Several scripts are available to check for invalid links and 404 pages, but what about redirects?

This script utilizes Google Apps Script's UrlFetchApp to check if an ad has has a redirect response code (3xx). If so, the script will fetch the new URL. Since Google Ads Scripts cannot edit existing ads, the ad with the old URL will be paused and its content is placed into a new ad within the same adgroup. This will be done for ETAs and RSAs.

Instructions:

  • This is an MCC script so you have to add the accountId.
  • Before running this script it is advised to run an example to check the actual changes and check te log files for additional information.
The script
/*
  Redirect follower v2.1 by Bas Baudoin
  
  This scripts replaces ETA/RSA final URLs with 301/302 redirected URL if available
  
  Instructions:
  - MCC script
  - Change account ID
  - Run example, check logs
  
  Todos
  - Non-domain urls
  - Extensions
*/

var accountId = 'XXX-XXX-XXX'

// placeholders
var urlCombos = {}
var checkedUrls = {}

// functions - do not alter ************************************************************

function main() {
  var account = AdsManagerApp.accounts().withIds([accountId])
  Logger.log(account.get().next().getName())
  account.executeInParallel('updateAds')
}

function updateAds(urls) {
  var adSelector = AdsApp.ads()
    .withCondition('Status = ENABLED')
    .withCondition("AdGroupStatus = ENABLED")
    .withCondition("CampaignStatus = ENABLED")
    .withCondition("Type IN [EXPANDED_TEXT_AD, VERSATILE_TEXT_AD]")
    .get()

  while (adSelector.hasNext()) {
    var ad = adSelector.next()
    var finalUrl = ad.urls().getFinalUrl()
    var adGroup = ad.getAdGroup()
    var adType = ad.getType()

    // check url availability or add to objects
    findRedirectUrl(finalUrl)
    var hasNewUrl = urlCombos[finalUrl]
    var hasNoNewUrl = checkedUrls[finalUrl]
    
    if (hasNewUrl) {
     
      // Recreate ETA
      if (adType == 'EXPANDED_TEXT_AD') {
        Logger.log('new ETA in ' + ad.getAdGroup().getName())
        var eta = ad.asType().expandedTextAd()

        var path1 = eta.getPath1() || ''
        var path2 = eta.getPath2() || ''
        var headline3 = eta.getHeadlinePart3() || ''
        var description2 = eta.getDescription2() || ''
        //var labelIterator = eta.labels().get()
        var labelIterator = ad.labels().get()

        Logger.log('ad: ' + finalUrl + ' - ' + hasNewUrl)

        var adOperation = adGroup.newAd().expandedTextAdBuilder()
          .withHeadlinePart1(eta.getHeadlinePart1())
          .withHeadlinePart2(eta.getHeadlinePart2())
          .withHeadlinePart3(headline3)
          .withDescription1(eta.getDescription1())
          .withDescription2(description2)
          .withPath1(path1)
          .withPath2(path2)
          .withFinalUrl(hasNewUrl)
          .build()
        
        var newAd = adOperation.getResult()

        while (labelIterator.hasNext()) {
          var label = labelIterator.next()
          var labelText = label.getName()
          newAd.applyLabel(labelText)
        }

        ad.pause()

        // Recreate RSA
      } else if (adType == 'VERSATILE_TEXT_AD') {
        Logger.log('new RSA in ' + ad.getAdGroup().getName())
        var rsa = ad.asType().responsiveSearchAd()

        var headlines = rsa.getHeadlines()
        var descriptions = rsa.getDescriptions()
        var labelIterator = rsa.labels().get()
        
        Logger.log('ad: ' + finalUrl + ' - ' + hasNewUrl)

        var rsaOperation = adGroup.newAd().responsiveSearchAdBuilder()
          .withHeadlines(headlines)
          .withDescriptions(descriptions)
          .withFinalUrl(hasNewUrl)
          .build()

        var newAd = rsaOperation.getResult()

        while (labelIterator.hasNext()) {
          var label = labelIterator.next()
          var labelText = label.getName()
          newAd.applyLabel(labelText)
        }
        ad.pause()
      }
    }
  }
  Logger.log('Final results')
  Logger.log(urlCombos)
  Logger.log(checkedUrls)
}

function findRedirectUrl(finalUrl) {
  if (urlCombos[finalUrl] || checkedUrls[finalUrl]) {
    //Logger.log('Url already checked')
    return false
  }
  
  var response = UrlFetchApp.fetch(finalUrl, { followRedirects: false, muteHttpExceptions: true })
  var responseCode = response.getResponseCode()
  var newUrl = response.getHeaders()['Location']
  
  if (!newUrl) {
    checkedUrls[finalUrl] = 'checked'
  }

  if (!responseCode) {
    Logger.log('no response code')

    // redirect starts with 3
  } else if (responseCode.toString()[0] == '3') {
    if (newUrl.indexOf('http') >= 0) {
      urlCombos[finalUrl] = newUrl
      return true
    } else {
      checkedUrls[finalUrl] = 'checked'
      //Logger.log(newUrl + ' does not contain http')
    }
  }
  return false
}
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 is all about sharing knowledge. In the current market, PPC specialists like to keep their knowledge and experience to themselves. We're convinced that sharing knowledge can ensure that everyone gets better at their work. We want to change this by sharing our knowledge about scripts with everyone.

Do you also want to contribute? We are open to new ideas and feedback on everything you find on Adsscripts.com.

Contact us

Training &
Workshop
Contact us!
Adsscripts Training & Workshop