As of 2018 I am no longer associated with both The Washington Post and this project.

Overview

The professional services team on Arc Publishing spends a lot of time building client sites, with varying degrees of complexity. As a result, we often have opportunities to iterate on the features we create as we learn from our experiences and grow as a team.

The Washington Post

Advertisements are one area we’ve had a lot of opportunity to iterate on. Almost all of our clients need to display them — and each publication has its own set of requirements and rules. As a team, we often found ourselves writing unique ad code for each client, which wasn’t ideal. It took up a lot of our developer’s time and the code maintenance was unwieldy due to the variations. Unique implementations also made it difficult to onboard new developers onto projects and have them work tickets related to advertisements, due to either a lack of documentation or lack of knowledge about how advertisements work. We eventually decided that something should be done about this.

We Made a Library

Our team’s solution was to abstract our advertisement logic into a new library we’ve dubbed ArcAds. ArcAds is a wrapper for DFP that simplifies and standardizes advertisement logic in a way that makes sense in the context of large-scale publishers. We created ArcAds to simplify the process of displaying advertisements, allowing our developers to focus on the placement of the creatives instead of worrying about making the actual advertisement request. We’ve combined our experience and the feedback we’ve received—from both client developers and ad managers—and now what used to take us several months, takes us only an hour or less to set up with ArcAds.

Installing ArcAds is really just a matter of including a script file in your page’s head and calling the class constructor to request an ad. However, ArcAds can also be installed via a package manager for more JavaScript-oriented projects. Because we wanted ArcAds to work with as many different types of projects as possible, we wrote the library in vanilla JavaScript instead of relying on a framework.

const arcAds = new ArcAds({
  dfp: {
    id: '123',
  },
})

After initializing ArcAds, you can simply call the registerAd method to get the advertisement to display. This method accepts an object with data about the advertisement, including the size, id and targeting parameters. Everything you need to get an advertisement to load is managed here.

arcAds.registerAd({
  id: 'ad-123', // The id should correspond with a HTML element on the page with the same id
  slotName: 'hp/hp-1',
  dimensions: '[[300, 250], [300, 600]]',
  display: 'mobile',
  targeting: {
    section: 'weather',
  },
})

ArcAds can even register multiple advertisements at once using the registerCollection method. This is useful for registering multiple advertisements at once in the page head, which can improve page performance. In an environment where each second can make or break a news story’s user experience, registering ad calls in one fell swoop provides critical improvements.

arcAds.registerCollection(
 [{
    id: 'ad-123',
    slotName: 'hp/hp-1',
    dimensions: '[[300, 250], [300, 600]]',
    display: 'all',
    targeting: {
      section: 'homepage'
  },
  {
    id: 'ad-456',
    slotName: 'hp/hp-2',
    adType: 'cube',
    dimensions: '[[300, 250]]',
    display: 'mobile',
    targeting: {
      jaffa: 'cakes'
    }
  }]
)

ArcAds can also handle DFP size mapping, a relatively new functionality within DFP itself. To enable it, you can configure the registerAd call to include more sizes and then configure an optional sizemap parameter which corresponds each set of dimensions to a screen width. This allows ad managers to serve the right-sized ad on any screen size, even if a user resizes his or her browser window. All of the resizing and refreshing logic is baked into ArcAds; besides the registerAd call, there’s nothing else a developer needs to set up.

arcAds.registerAd({
  id: 'div-id-123',
  slotName: 'hp/hp-1',
  adType: 'cube',
  dimensions: `[ 
      [[970, 250], [970, 90]], 
      [[728, 90]], [[320, 100]] 
    ]`,
  targeting: {
    section: 'weather',
  },
  sizemap: {
    breakpoints: '[ [1280, 0], [800, 0] ]', // 1280 wide will load either a 970x250 or 970x90.
    refresh: true, // Determines if the advertisement should refresh when a breakpoint is passed, or only determine on load
  },
})

What about Header Bidding?

ArcAds also supports header bidding, which is an increasingly popular request from Arc powered clients. At this time, ArcAds unofficially integrates with Amazon TAM/A9 and also has components that interact with the Prebid.js wrapper. Enabling header bidding in ArcAds is as simple as including a parameter when initializing ArcAds.

const arcAds = new ArcAds({
  dfp: {
    id: '123',
  },
  bidding: {
    amazon: {
      enabled: true,
      id: '123',
    },
  },
})

arcAds.registerAd({
  id: 'ad-123',
  slotName: 'hp/hp-1',
  adType: 'cube',
  display: 'desktop',
  dimensions:
    '[ [[970, 250], [970, 90], [728, 90]], [[728, 90]], [[320, 100], [320, 50]] ]',
  sizemap: {
    breakpoints: '[ [1280, 0], [800, 0], [0, 0] ]',
    refresh: 'true',
  },
  bidding: {
    amazon: {
      enabled: true,
    },
  },
})

We’ve also configured a way for ArcAds to integrate with other vendors using a lifecycle method that occurs right before an advertisement is about to load. To handle this, pass a prerender function to the registerAd call. The prerender functionality is especially useful for integrating with services that require you to attach targeting parameters to the advertisement request, such as third party DMP platforms and other header bidding services that don’t integrate with Prebid.js or Amazon.

arcAds.registerAd({
  id: 'ad-123',
  slotName: 'hp/hp-1',
  dimensions: '[[300, 250], [300, 600]]',
  prerender: window.adFunction, // This function will fire right before the advertisement loads
})

ArcAds expects the prerender function to return a resolved promise. Once the promise is resolved, the advertisement will be displayed.

window.adFunction = function (ad) {
  return new Promise(function (resolve, reject) {
    // The 'ad' arguement will provide information about the unit such as the GPT slot, the id, and the sizes which are about to load.
    console.log(ad)

    // The promise should be resolved when you're ready to resume the display of the advertisement.
    resolve()
  })
}

Contributing

Every decision we’ve made with ArcAds has stemmed from a real-world requirement — and so far we’ve had great success with it in our implementations. As a result, we’ve decided to open source ArcAds, in order to collaborate and see how other developers can make use of the library. We welcome any feedback and contributions to the project, and we’ve even setup a contributors guide for those who would like to help out.