# Write an OnExtraction Middlewares for Doubleclick Ad Server

This article explains the steps to implement an OnExtraction Middleware for Doubleclick Ad Server Provider.

# Doubleclick Ad Server Provider

Doubleclick Ad Server has different properties available at its schema (opens new window) and one of them is the json.targeting property. For this example, we will add the targeting found within a script tag inside the tenant's HTML source code.

To extract values from the original HTML of a page, we use the OnExtraction Middleware.

# OnExtraction Middleware Implementation guide

First of all, locate where the data that we want to extract from the HTML client source code is.

This example shows how a configuration for category and tags targeting can look like in a tenant's source code:

<script>
    window.googletag = window.googletag || {cmd: []};
    googletag.cmd.push(function() {
        //...
            googletag.pubads().setTargeting("category", ["news"] );
            googletag.pubads().setTargeting("tags", ["electricity","eskom","featured","south africa"] );
        //...
    });
</script>

Our objective is to extract this information and send it to the Ad Server in an object that can be merged with the one defined at the inventory. So, it has to partially match with the Config object of Doubleclick (opens new window). In this case, the result object will be something like this:

{
    json: {
        targeting: {
            category: ["news"],
            tags: ["featured","schools","south africa","teachers"]
        }
    }
}

# Set up

Once you found the data you need to extract, the next step is to set up all that we need to create our middleware.

First, create the src/middlewares/inventory/dfpTargetingDetector/on-extraction.ts file for the implementation, and the src/middlewares/inventory/dfpTargetingDetector/on-extraction.test.ts file for the test.

Then, install:

  • Middleware test utils package
npm i --save-dev @marfeel/middlewares-test-utils
  • Middleware types package
npm i --save-dev @marfeel/middlewares-types
  • and Doubleclick Adserver Provider package (unless it's already installed)
npm i @marfeel/adserver-providers-doubleclick

# Create a test

We recommend using a test-driven approach so, let's create the tests first.

Run the npm run create:fixtures command to automatically generate the fixtures.

You can check the How to create tests for Middleware (opens new window) article to see in detail how to create a test for an onExtraction middleware.

We will need to load the fixture we have created and run our middleware with it. Then, we must verify that the result obtained from executing it is an object like the one we need.

//on-extraction.test.ts
import { loadFixture, runMiddleware } from '@marfeel/middlewares-test-utils';
import { onExtraction } from './on-extraction';

describe('Doubleclick', () => {
    describe('OnExtraction', () => {
        test('returns the dfp targeting', async() => {
            const document = await loadFixture('news-when-learners-return-to-school-what-date-matric-exam-results-released.html');

            const result = await runMiddleware(document, onExtraction);

            expect(result).toEqual({
                json: {
                    targeting: {
                        category: ['news'],
                        tags: ['featured', 'schools', 'south africa', 'teachers']
                    }
                }
            });
        });
    });
});

# Middleware Implementation

Once the test is ready, you need to obtain the data from the script.

For do it we can use the Middleware helper functions to mock the window object and execute the scripts that will populate the mocked object with the data we need to retrieve.

First we are going to create the mock of the object that the script uses. This object has to have everything necessary for the script to run without failure and with all the functions that are used in the script even they are not relevant for us.

We configure the function setTargeting to be able to populate the targeting object with the values that are sent by parameter since these are the ones that we want to collect.

    const targetingObject: { 
        [key: string]: string; 
        [key: string]: Array<string>; 
    } = {};

    const googletag = {
        targeting: targetingObject,
        cmd: {
            push: function (f: () => void) {
                f();
            }
        },
        setTargeting: function(key: string, value: Array<string>) {
            this.targeting[key] = value;

            return this;
        }
        //...
    };

We call the installMock method passing the object that we just created and the window property we want to retrive. And then we use the execute method to run the target script. As a parameter, we will add a string that partially matches the content of the script.

Once the script has run, it will have modified window.targeting with the values that we need, so they will be available at the mock object.

const mock: any = helpers.installMock(googletag, 'googletag');

helpers.execute('googletag.pubads().setTargeting');

const targeting = mock.targeting;

After obtaining the data from the script, you need the onExtraction hook to return the result as an object partially matching the Doubleclick Config type.

The final result will look similar to this example:

//on-extraction.ts

import { onExtractionFunction } from '@marfeel/middlewares-types';
import { Config } from '@marfeel/adserver-providers-doubleclick';

export const onExtraction: onExtractionFunction<Partial<Config>> = async ({ document, helpers }): Promise<Partial<Config>> => {
    const targetingObject: { 
        [key: string]: Array<string>; 
    } = {};

    const googletag = {
        targeting: targetingObject,
        cmd: {
            push: function (f: () => void) {
                f();
            }
        },
        setTargeting: function(key: string, value: Array<string>) {
            this.targeting[key] = value;

            return this;
        }
    };

	const mock: any = helpers.installMock(googletag, 'googletag');

    helpers.execute('googletag.pubads().setTargeting');
    
    return {
        json: {
            targeting: mock.targeting
        }
    };
};

Now, it's time to run npm test and validate the tests are passing.

To test the implementation in production pages, first run npm run build and then npm run middleware dfpTargetingDetector https://example.com/article-containing-dfp-targeting/.

# Connect the pieces

  1. Add the invokeMiddleware flag to the features.json and set it to true.
//features.json
{
  "features": {
    "invokeMiddleware": true
  }
}
  1. Add the middleware to the Ad Server on inventory.json. It should be always at the top level of the Ad Server Config and its name has to be the same name you used to create the middleware folder.
//inventory.json
{
    "placements": {
        "bottom_details_1": {
            "adServer": "dfp"
        }
    },
    "adServers": {
        "dfp": {
            "type" : "doubleclick",
            "slot" : "/123456/test.com",
            "middleware": "dfpTargetingDetector"
        }
    }
}

Now you can test the middleware with a tenant in your local environment or with a Preview Branch and check if the DFP calls contain the desired targeting.

WARNING

If you are replacing a Metadata Provider for an OnExtraction Middleware, remember to remove all the old Metadata Provider files and their references.

Here you can find a a real OnExtraction Middleware example (opens new window)