Skip to content

Instantly share code, notes, and snippets.

@codeorelse
Created January 6, 2016 10:25
Show Gist options
  • Save codeorelse/5e905f35a1b9942ef84b to your computer and use it in GitHub Desktop.
Save codeorelse/5e905f35a1b9942ef84b to your computer and use it in GitHub Desktop.
# Creatives that work with LemonPI
# To do
- backup gif? couldn't splash do this already? should we require it and mention it in the lemonpi-creative.json => nopes
- how should we indicate loading propositions failed? the creative will still call getPropositions(), and get an empty array. should there be some function a creative can call to check whether fetching propositions was successful? => the user should just check the respones value from getProposition() and getPropositions().
# Introduction
This document specifies what a (dynamic) HTML5 creative should look like in order to be used in LemonPI.
LemonPI can publish your dynamic HTML5 creatives to various ad servers. LemonPI takes care of turning the creative in the right format, the format each ad server understands. LemonPI also integrates the ability to retrieve dynamic content into the creative, when publishing (and previewing inside the LemonPI interface). Creatives uploaded to LemonPI must adhere to the rules below.
The creative is a zip-file containing the following files:
- `creative.js` (required), maximum 50*1024 bytes in size. This is the most important piece of the creative. More details about this creative can be found below.
- `*.png`, `*.jpg` (optional); these images can be referenced from the creative.
- `index.html` (optional), an example html file provided by you that references `creative.js` and will show the default/fallback (non-dynamic) behaviour of the creative. This file is not used when publishing the creative. It is just for stand-alone preview functionality. More rules about the format of this file can be found below.
- `lemonpi-creative.json` (required); meta-data about the creative; details below
Note: Fonts are not included in the creative. You should use an external service for this, e.g. a CDN.
Additional requirements:
- The assets must not be in subdirectories. All files should be in the root of the zip file.
- The total contents of the zip file (assets and script) should not exceed 200 kilobyte.
- The total number of files in the zip file (assets and script) should not exceed 15.
## `creative.js`
This JavaScript file will be included in a minimal HTML file that will be served by ad servers.
This code is executed immediately when the creative is loaded. However, the creative must not start displaying/animating immediately. Instead, it must set the function `window.lemonpi.start`, which is called as soon as the dynamic content has been fetched. The creative should start preloading any dependencies immediately when it is executed, so before the `start` function is called. Note that `start` may be called before preloading has completed. It is the task of the creative's `creative.js` to ensure it waits with animating until preloading is done (if so desired).
`Creative.js` should be utf-8 encoded.
### Click handling
The register should register clicks by calling `window.lemonpi.click`. The LemonPI javascript code will ensure the click is registered with the ad server's click tracker, the LemonPI click tracker, an optional 3rd party click tracker (specified when publishing from LemonPI to the ad server), and send the user/browser to the final landing page.
- `click()`, go to the default landing page as configured while publishing.
- `click(clickUrl: string)`, go to the url specified.
- `click(proposition: object)`, go to the clickUrl specified in the proposition object (`proposition.clickUrl`)
- `click(..., form: object)`, like above, but add the key/value parameters from the object to the final landing page url as query string parameters, e.g. `{mykey: "myvalue"}` would result in adding `&mykey=myvalue` to the final landing page url (which is constructed based on the first parameter).
### Dynamic Content
LemonPI retrieves dynamic content, specifically for the user the ad is being served to. You can retrieve the dynamic content with the following JavaScript functions provided by LemonPI, on the `window.lemonpi` object:
- `getPropositions(index)`, return all dynamic propositions for the given dynamic input `index` (`0` or `1`).
- `getProposition(index)`, return the single dynamic proposition for dynamic input `index` (`0` or `1`). Only the first of the propositions is returned. Should only be used when the creative only has a single dynamic input returning a single proposition.
A proposition is a JavaScript object. To illustrate, a typical proposition currently has the following keys (though this will likely change in the future):
- `title`, main text for the proposition.
- `clickUrl`, final landing page url when clicking on this proposition.
- `key`, LemonPI identifier of this proposition, used in the LemonPI click tracker to assign a click to this proposition.
- `imageUrl` (optional), image for this proposition.
- `logoUrl` (optional), additional image for this proposition.
- `description` (optional), more text for this proposition.
- `priceNormal` (optional), to be used for a price for this proposition.
- `stickerText` (optional)
- `custom1` (optional)
- `custom2` (optional)
- `custom3` (optional)
- `custom4` (optional)
The creative should gracefully handle situations where the `getProposition*` functions do not return propositions. This could happen when there are no propositions in LemonPI, or when LemonPI cannot be reached.
xxx for getProposition(), should we return {} or null when we have no proposition? {} is not falsy, so more annoying to check for in errors. but null.title will result in js errors.
xxx should we keep the `index` optional? requiring explicit index seems better to me.
## `lemonpi-creative.json`
The file `lemonpi-creative.json` contains meta-data about the creative. It should be JSON-encoded data. An example file:
```json
{
"version": 1,
"width": 300,
"height": 250,
"script": "creative.js",
"assets": ["123.png", "logo.jpg"],
"inputs": [
"scraper",
"country"
]
}
```
The fields:
Field | Type | Required | Description
----------- | ----------------- | --------- | -----------
version | int | Y | Specifies the version of this lemonpi-creatives.json file. This leaves room for forward compatibility.
width | int | Y | Width of the creative.
height | int | Y | Height of the creative.
script | string | Y | Name of script file. This is normally "creative.js". Note: this path should not contain a subdirectory.
assets | list of string | Y | List of files that should be served as part of the creative. Note: these paths should not contain subdirectories.
inputs | list of string | Y | List of dynamic inputs kinds required by this creative, in this order.
LemonPI ignores additional fields in the JSON file. Future versions may define behaviour for currently unused fields. To be future-proof, avoid using additional keys, or prefix/suffix them with the name of your organization.
## `index.html`
You don't have to provide an `index.html` in the creative. But you will probably want to test your creative with an HTML snippet that resembles the one created by LemonPI. Below is an example HTML file:
```html
<!doctype html>
<html>
<head></head>
<body>
<script>
window.lemonpi = {};
// this is normally set by lemonpi to properly handle the click, going through all relevant click trackers
window.lemonpi.click = function() {
alert('Click: '+JSON.stringify(arguments));
};
// fill this in with data relevant for your creative
var testdata = [
// first input
[
// {key: 'test', title: 'test', clickUrl: 'http://localhost'}
],
// second input
[
// ...
]
]
// these functions are normally provided by LemonPI, where they return actual dynamic data
window.lemonpi.getPropositions = function(index) {
return testdata[index];
};
window.lemonpi.getProposition = function(index) {
return testdata[index][0];
};
// INCLUDE YOUR creative.js HERE
// it should set window.lemonpi.start to a function that kicks off your animation.
// now start the banner/animation. this is not part of your creative.js, this is what lemonpi adds when publishing a creative.
window.lemonpi.start();
</script>
</body>
</html>
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment