CPEx Package
The package is a library for filling ad-tech gaps in solutions of our publishers. They are using multiple providers of ad servers, servicing libraries which interface with them, render in a different ways, might need to add header-bidding data etc. To make things simple to load (one file), whenever (async) and to debug, it tries to provide well named and documented methods, which log their usage and data to console (when using debug url param). It also adds an error reporting feature.
The full API documentation lives at: https://cdn.cpex.cz/package/docs (production version)
Features
- Settings ― main.js loads files from CDN, which configure everything
- [Publisher] - custom code (catching, rendering) for specific publishers
- AdServer ― (optional) multiple versions for unifying different adserver providers
- Headerbidding ― (optional) additional client-side source of ads
- Rendering ― (optional) some publishers/adservers render ads themselves, some don't
- Formats ― handling of custom ad formats
- Analytics ― sending of useful anonymous metadata to CPEx servers
- AB testing ― an option to load different settings based on a random key (internal or external)
Plus there is Playground, a website to test everything, both locally and live
Flow
- Ad units are present: It starts with ad positions in the page which are defined in two ways. One in the actual page by the publisher, for adserver. Seconds for header-bidding by CPEx, in website settings (see Settings readme).
- Settings are loaded: They configure whatever is needed in package sub-modules and their prerequisites.
- (Optional) Header-bidding is run: It's bid data is added to the ad unit data, to be sent to the adserver.
- AdServer is called: It figures out the most profitable ads to serve to the user.
- Rendering: Creatives are returned from the adserver to be rendered. Now it gets complicated, read Rendering readme.
- Catching: Special formats should be recognized (catched) based on their size and rendered outside of their ad element (typically into the page background)
- Custom format enrichment: Once the special format is catched and rendered into the proper element, it's subtype is handled by special rendering code. Usually a template to be filled with data.
Commands
| NPM run | Description |
|---|---|
test |
Runs tests in the console, watches for changes |
build |
Builds the package, places it into /dist and playground/assets |
deploy |
Builds the package, backs up cdn version, publishes to CDN, purges cache |
dev |
Builds the package, starts Playground, watches for changes |
document |
generates technical documentation |
Prerequisites
Javascript
- This package uses ES6, without transpilation
- HTML5 doctype is expected
- HTTPS protocol is expected
Libraries
- Every adserver requires an accompanying library. Check out the AdServer adapter readme for a complete list of supported adserver providers and their libraries.
Development
- This package uses modern ES6 modules (
import). If legacy CommonJS module (require) has to be added,createRequirefunction can be used.
Implementation
Add the following to the website html, with a tag manager.
<link rel='preconnect' href='https://cdn.cpex.cz' crossorigin>
<script>
window.cpexPackageConfig = {
publisherSettingsPath: 'https://cdn.cpex.cz/settings/production/cpex.js',
websiteSettingsPath: 'https://cdn.cpex.cz/settings/production/cpex/playground.cpex.cz.js',
autoInit: true, // optional, defaults to true,
texts: { // optional translations
ad: 'reklama',
vignetteClose: 'zavřít reklamu',
slideupClose: 'Zavřít ✕'
}
}
document.head.appendChild(Object.assign(document.createElement('script'), { src: 'https://cdn.cpex.cz/package/cpex-package' + (window.location.href.indexOf('cpxdebug') > -1 ? '.js' : '.min.js') } ))
</script>
Debugging
Even with source maps the debugging experience with current browser dev tools is pretty bad. The solution is to use Requestly plugin to switch from the minified version of the code to the full unminified. Here is the rule I'm using: https://app.requestly.io/rules/#sharedList/1638969083447-CPEx
Lifecycle methods
Modules need be able reloadable, therefore there needs to be a naming convention
constructoronly handles synchronous variablesloadhandles asynchronous calls (mainly loading of prerequisite file)runhandles the current page view and can be repeated
Single page apps
cpexPackage.init()this method allows you to start loading at a later time, when usingautoInit: falsein cpexPackageConfig.cpexPackage.refresh()reloads adscpexPackage.reload()reload package completely (in case of settings changes)
Events
Can be used to trigger additional publisher specific code.
Events are triggered at window event target.
cpexPackageAdded: Triggered when package has been added to the pagecpexPackageLoaded: Triggered when package finishes loadingcpexBidsAdded: (sasTracker) Triggered after HB completes and bids are added to AdsObjectcpexAuctionDone: Triggered when HB auction is done and bids are processedcpexAuctionDoneVideo: Triggered when HB auction is done and video bids are foundcpexAdRendered: Triggered when package renders an adcpexAdReRendered: Triggered when package calls prebid to render ad into an already rendered "service creative" (odbavovací kreativa)cpexPrebidConfigured: Triggered when prebid is configured, right before bids are requestedcpexSlideupClosed: Triggered when closing slideup formatcpexVignetteClosed: Triggered when closing vignette format
Error reporting
Uses service Honeybadger.io
Custom message: Honeybadger.notify('Hello from JavaScript')
Integration into the library is done by a custom fork, we had to add ESM build target.
Repository here: https://github.com/Czech-Publisher-Exchange/honeybadger-js
Playground
This repository contains a test website called Playground. It uses simple but reactive framework Svelte.
After running npm run dev command it's served at localhost:5000. It watches for code changes and reloads the page. You can try all changes there. After you push to master branch to origin, CI is run and the page is also deployed live at playground.cpex.cz