Platypus Header

Platypus Innovation Blog

15 May 2017

How to make a lightbox in DoubleClick for Publishers (DfP), or Wrestling with an AdTech Monster

If you're working in adtech, you'll probably encounter DoubleClick for Publishers (DfP) - it is the most common publisher-side adserver (or SSP). We've recently produced a version of Good-Loop for DfP. This article lists the various booby traps we found along the way. For further details, see our scars.

First up: If you use an adblocker, turn it off. Understandably, that can break DoubleClick, given that it is an adserver.

So you want to write an expanding lightbox -- well DoubleClick supports that, via DoubleClick Studio Enabler (Enabler.js), and how lovely, they even provide a template to get you started.
Except it is broken. We modified the template and it didn't work. We used the original exactly as provided, and it did not work. As far as I can tell, this is obsolete and broken code, they just forgot to update the documentation. Hidden in a disused basement of the DoubleClick website, inside a cabinet labelled "beware of the leopard", there is a note to say that SafeFrame is the preferred method. Do not use DoubleClick Studio Enabler -- use SafeFrame instead.

SafeFrame requires you to know the size of the ad slot. And it provides a query for finding out page size info. However this is not as useful as you'd hope, because you have to specify the slot size first, before you can query the page size. So you need to pass that info into your creative -- which is done via a couple of macros: %%WIDTH%% and %%HEIGHT%%.

You'll need to use the SafeFrame ext.geom() method to provide the right expansion size. Beware that this can be affected by timing issues. Don't call it until you're about to do the expansion.

At the time of writing, DfP's implementation of SafeFrame was slightly flaky on iOS. To get reliable results, we put in code to retry the lightbox expansion (and the close) a few times, stopping if your handler receives a success message.

You'll probably want to know where your advert is going -- but DfP doesn't tell you by default, because: I don't know. You can get this by adding the %%SITE%% macro to your script url. As an example, Good-Loop's final DfP creative looks like this:

<script src="//"></script>

The next gotcha is the DfP Preview feature. This handy feature provides a link to see your creative in situ. Except DfP preview does not work for rich media ads. This is due to a bug in DfP: the preview simply doesn't properly support the lightbox features -- although the real DfP iframe does. This makes preview confusingly useless for lightbox ads like Good-Loop. So avoid Creative -> Preview.

So how can you preview an advert? The best approach we found was to setup a very targeted line-item. In DfP, create a line-item that targets a specific (and rare) device. Then in your Chrome browser, open the developer console, toggle device mode, and set Chrome to emulate that device type.

An annoying feature of DfP is that it will sometimes fill slots with random adverts, rather than the line item you want. Swearing and mashing the settings is one solution.

Another source of frustration is the delays. Edits in DoubleClick can take 10 minutes to percolate through the slow-as-treacle systems and actually take effect. This multiplies the pain of the trial-and-error stress test that is working with DfP. To minimise this, we moved our html code to being dynamically generated, with the DoubleClick creative reduced to a single .js script tag.

Now we're serving adverts...

Bugs from the host-page CSS: It's easy to break a SafeFrame's ability to expand to full-page. A common css rule goes something like:
iframe, some other element types {
 max-width: 100%;

Looks reasonable, but it restricts the iframe's width to 100% of the parent element's - which is almost always very small. Your SafeFrame does an expand... to the same size it was before.

If the publisher is cooperative, they can fix this by adding a very specific CSS rule such as:

iframe[id^='google_ads_iframe_'] { max-width: none; }

Good-Loop Unit