express-ads
Version:
Ads distribution and management module for Express
340 lines (258 loc) • 16.5 kB
Markdown
Express Ads
===========
*Express Ads* provides a lightweight simple way to deliver ads in an Express-based web site. It works with any template engine and
provides a nice admin interface.
# Live demo
Visit [demo.eas.rocks](http://demo.eas.rocks/) . The full source code of the live demo site is available from [github](https://github.com/mi-g/express-ads-demo). It may be useful to better understand how to implement *express-ads* in your web site.
# Features
- Multiple concurrent campaigns
- Multiple banners per campaign
- Multiple creatives per banner
- Several campaign types:
+ Number of prints within a period
+ Number of click within a period
+ Recurrent prints (like 10000 prints per day)
+ Recurrent clicks (like 100 clicks per day)
+ Background (weighted display on available inventory)
- Ads are distributed evenly over the period
- Page and session capping per banner and/or campaign
- Country/OS/Browser filtering
- Campaign optional start/end dates
- Real time prints and clicks statistics
- Full admin interface integrable to the site's existing admin
- Not relying on a specific database
- Robust to ad-blockers (ads served from the site itself)
- Extensible via add-ons to serve ads for external platforms
## Screenshots
[](https://eas.rocks/images/screenshot1.jpg)
[](https://eas.rocks/images/screenshot3.jpg)
# Using Express Ads (short version)
## App setup
```
var app = express();
...
require('express-ads')(app,{});
...
app.get('/content-path', function (req, res) {
res.render(someTemplate, {
ad: req.deliverAd,
});
});
app.listen(3000);
```
## Requesting an ad
### Using Jade as template engine
```
p
| Ipsum lorem ...
| !{ ad('area-name') }
p
| Ipsum lorem ...
```
### Using EJS as template engine
```
<p>Ipsum lorem ...</p>
<%- ad('area-name') %>
<p>Ipsum lorem ...</p>
```
## From the admin interface
- Open `http://your-domain.com/eas/admin'
- Create an area specifying the size
- Create a banner
- Add the area to the banner
- Setup the banner link
- Add one or more images to the banner with same size
- Create a campaign
- Add the banner to the campaign
- Reload the content page, ads should be displayed
# Using Express Ads (detailed version)
## Setting up in your web site
Setup express-ads in your application using:
```
var app = express();
...
require('express-ads')(app,options);
```
after doing so, the `req` object will contain the following new fields:
* `deliverAd`: a function that returns the HTML code to display (or not) an ad
* `expressAds`: access to global express-ads service
`deliverAd` takes 2 parameters: *areaName* and an optional *adParams* and returns immediately the HTML code for the ad to display. Note that it might be an empty string if the module decided that no ad should be displayed.
* `areaName` is the human name of an area that must have been created from the admin interface
* `adParams` an object with the following fields:
| Param | Default | Description |
| ----- | ------- | ----------- |
| `styles` | `null` | an object containing CSS styles and values to display the ad container |
| `classes` | `null` | an array of classes (as strings) to be applied to the ad container |
| `tag` | `null` | if set, the HTML element to be used for the ad container. By default, `<p>` is used for text inventory areas, `<div>` for other inventory types |
Note that those parameters (styles, classes, tags) can also be set tuned from the admin interface. It's up to you to choose whatever styling method you want to use.
`expressAds` is an object that provides access to a number of services:
| Param | Description |
| ----- | ----------- |
| `adminUI` | a function that returns the entire admin interface HTML code |
| `styles` | an array of strings representing the stylesheets to be included in the admin page |
| `stylesHTML` | like `styles` formatted as a single HTML string that loads the stylesheets |
| `scripts` | an array of strings representing the scripts to be included in the admin page |
| `scriptsHTML` | like `scripts` formatted as a single HTML string that loads the scripts |
| `saveStats` | a function to save manually the current stats. It takes a callback as parameter that is called when the save operation is done. Note that stats are automatically saved every minute, so this function is only useful when doing a shutdown of the application if you don't want to lose the last minute of stats |
When doing `require('express-ads')(app,options)`, `options` is an object that can contain the following fields:
| Param | Default | Description |
| ----- | ------- | ----------- |
| `path` | `"/eas"` | the base URL path where express-ads services are attached to |
| `adminPath` | `null` | by default (`null`), the express-ads admin interface can be accessed from `path`+`/admin` (if you did not change `path`, it is `/eas/admin`). You can set `adminPath` to any other path value, like `"/admin/eas`" |
| `auth` | passthrough function | a `function(req,res,next)` to authenticate the access to the express-ads admin interface. By default, this function is a passthrough (it calls `next()` directly). You can implement your own authenticator here (using *passport* for instance) or rely on your site's default security system to protect the path to the admin page. For instance, many sites protect globally everything under `/admin`, so if you define `adminPath` to `"/admin/eas"`, you are safe and you can set the `auth` function to `function(req,res,next) { next(); }` |
| `staticMaxAge` | `"1h"` | the cache duration for static resources |
| `rollBacklog` | `1000` | the service maintains a cache for the last events, so it can determine a statistical event rate used to serve ads evenly over a period |
| `rollExpire` | `172800000` | default corresponds to 2 days. Older entries are removed from the roll cache |
| `adblockerDetection` | `true` | whether the adblocker detection is activated. You can filter banners based on whether the user has an adblocker or not |
| `files` | | an object containing various data pathes (see below) |
| `files.ads` | `"ads.json"` | file where ads configuration data are kept |
| `files.stats` | `"stats.json"` | file where stats are kept |
| `files.images` | `"ads/images"` | directory where banner images are stored |
| `files.tmp` | `"ads/tmp"` | directory where banner images are temporarily stored |
| `debugDeliver` | `false` | if set to `true`, traces are printed to the console when an ad is to be picked for delivery |
| `debugData` | `false` | if set to `true`, the admin interface will display an additional containing the raw JSON data for ads config and stats |
| `debugLiveTemplate` | `false` | if set to `true`, it won't be necessary to restart the server app to see changes in the admin user interface |
| `imageMagick` | `false` | use *ImageMagik* to manipulate banner images. On *Ubuntu*, you can install *ImageMagick* with `apt-get install imagemagick` |
| `addons` | `null` | an array of add-on modules. See below *Extending express-ads* |
| `allowedSizes` | see below | an object describing the available inventory areas sizes. A new size can be added by specifying a corresponding entry in `allowedSizes`, for instance `"123x456":1`. An existing size can be removed by setting its value to *0*: `"468x60":0` |
| `allowUpload` | `true` | is uploading local image files allowed |
plus a number of parameters dedicated to integrating the express-ads admin interface to the site's admin (see below).
The default value for `allowedSizes` is:
```
allowedSizes: {
"120x240": 1,
"120x600": 1,
"120x60": 1,
"120x90": 1,
"125x125": 1,
"160x600": 1,
"180x150": 1,
"234-60": 1,
"240x400": 1,
"250x250": 1,
"300x250": 1,
"336x280": 1,
"468x60": 1,
"728x90": 1,
"88x31": 1,
}
```
Note that additional sizes declared by addons are automatically made available.
## Display an ad in the template
Whether you use Jade, EJS or any other templating system, you need to have access from your template to the express-ads *deliverAd* function:
```
app.get('/content-path', function (req, res) {
res.render(someTemplate, {
ad: req.deliverAd,
});
});
```
You can then request the ad display doing `!{ ad('area-name') }` (Jade) or `<%- ad('area-name') %>` (EJS).
It is a better practice to pass the styling options to the express-ads API `<%- ad('area-name',{classes:['ad-wrapper']}) %>`, rather than providing your own externally `<div class='ad-wrapper'><%- ad('area-name') %></div>` because if no ad is to be displayed (`ad()` returning an empty string) you might be left with unwanted paddings, margins, borders, ...
## Express-ads admin interface integration
By default, once express-ads is setup in your site, you can access the admin interface on `http://mysite.com/eas/admin`, however, since your site is likely to have its own admin user interface, you may want to integrate express-ads into it to keep a common look and feel.
The idea is to provide your own admin template and layout and insert it into your page:
```
app.get('/admin/ads-management', function (req, res) {
res.render('ads-management-template, {
expressAds: req.expressAds,
});
});
```
and in the template (Jade version):
```
...
body
...
| !{ expressAds.adminUI() }
...
| !{ expressAds.scriptsHTML }
| !{ expressAds.stylesHTML }
```
or (EJS version):
```
...
<body>
...
<%- expressAds.adminUI() %>
...
<%- expressAds.scriptsHTML %>
<%- expressAds.stylesHTML %>
</body>
</html>
```
`expressAds.adminUI()` returns as a single string the whole required HTML to build the user interface, `expressAds.scriptsHTML` and `expressAds.stylesHTML` contains the scripts and styles for this page to run.
The express-ads admin page makes use of several common libraries that you may already have setup in your site template. You can prevent the scripts and styles to be loaded twice by specifying parameters `adminScripts` and `adminStyles` into `options` when calling `require('express-ads')(app,options)`.
The admin UI integration specific option parameters are:
| Param | Default | Description |
| ----- | ------- | ----------- |
| `standaloneAdminUI` | `true` | if set to `false` a default admin page is not provided |
| `adminScripts` | see below | an object to change or remove loaded scripts |
| `adminStyles` | see below | an object to change or remove loaded styles |
For instance, calling `require('express-ads')(app,{adminScripts:{jquery:null})` ensures `expressAds.scriptsHTML` does not contain the code to load *jquery*, assuming it is loaded by your own means.
The default list of scripts libraries is:
| Library | value |
| ------- | ----- |
| `jquery` | `https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js` |
| `angular` | `https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js` |
| `angularSanitize` | `https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular-sanitize.min.js` |
| `bootstrap` | `https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js` |
| `moment` | `https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js` |
| `bootstrapDateTimePicker` | `https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/js/bootstrap-datetimepicker.min.js` |
| `uiSelect` | `https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.13.2/select.min.js` |
For styles:
| Library | value |
| ------- | ----- |
| `fontAwesome` | `https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css` |
| `bootstrap` | `https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css` |
| `bootstrapDateTimePicker` | `https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/css/bootstrap-datetimepicker.min.css` |
| `uiSelect` | `https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.13.2/select.min.css` |
You can see an example of *express-ads* admin page integration in the [exskel](https://github.com/mi-g/exskel) (a skeleton for Express-based web sites).
## Using the admin interface
This is pretty straight forward.
Basically you create an inventory area, specifying a size. Then, you create a banner, specifying type *Image*, fill-in details, including a target link, indicate which areas this banner can be displayed to, add images to the banner (only images with a size that fit an inventory area will be used), specify filters if you want to. Next, create a campaign, specifying a type, for instance, *Background*, the banners you want to use for this campaign and you are all set, express-ads should start delivering ads.
There are a few things that may not be obvious though.
When using a *Text* banner, that may contain several texts to be chosen randomly, if you simply specify a text like `This is the text of my ad`, the whole sentence will appear as a link. If you do `This is the [[text]] of [[my ad]]`, `text` and `my ad` will appear as links (to the target link you specified for the banner), while the remaining words will show up as normal text.
When specifying a target link for a banner, you can use the following placeholders:
| Placeholder | Replaced with |
| ----------- | ------------- |
| `{{INV}}` | the inventory area id |
| `{{CAM}}` | the campaign id |
| `{{BAN}}` | the banner id |
| `{{IMA}}` | the creative (specific image or text) id |
| `{{ALL}}` | equivalent to `{{INV}}.{{CAM}}.{{BAN}}.{{IMA}}` |
# Extending express-ads
Express-ads can be extended using add-ons. There are currently 2 add-ons modules:
* [express-ads-adsense](https://github.com/mi-g/express-ads-adsense) for serving ads from AdSense
* [express-ads-chitika](https://github.com/mi-g/express-ads-chitika) for serving ads from Chitika
## Using an express-ads add-on
When calling `require('express-ads')(app,options)`, `options` must contain fields `addons` with an array of add-on modules as value. For instance:
```
require('express-ads')(app,{
...
addons: [ require('express-ads-adsense'), require('express-ads-chitika') ]
});
```
When creating a new banner, additional types will be available, in this case `AdSense` and `Chitika`. Depending on the add-on requirement, you may have to setup addtional configuration from the admin interface, like the publisher ID and slot ID, either globally from the *Express Ads* tab, or per banner in the banner settings panel.
## Developing an add-on
If you want to develop an add-on for another platform, the good news is that it is very simple. The best way is to start from an exiting add-on like [the one for AdSense](https://github.com/mi-g/express-ads-adsense).
Rename `adsense.js` to something more appropriate, and edit the file to match your needs. `exports.settings` and `exports.bannerSettings` define the settings for the add-on, repectively globally and per-banner. There are 3 parameter types you can use:
| Parameter | Description |
| --------- | ----------- |
| `text` | a single line text parameter |
| `longtext` | a text over several lines |
| `checkbox` | a checkbox parameter |
The file `template.ejs` describes (in EJS templating language) the HTML code that will be generated.
When you define a parameter with name, say `myparam` in `settings`, it's value is available from the template using `<%= settings.myparam %>`. If defined in `bannerSettings`, you can read it as `<%= banner.addon.myparam %>`.
Other variables are also available in the template:
| Parameter | Description |
| --------- | ----------- |
| `size` | an object with field `width` and `height` corresponding to the current area |
| `campaign` | the full campaign object |
| `banner` | the full banner object |
| `inventory` | the full inventory object |
# Limitations
- Express Ads is not intended to support multiple users editing ads from the admin interface at the same time
- In this early version, only plain images and text ads are supported, not videos. Add-ons allow serving ads from external platforms
# Supporting Express Ads
This code is free for you to use. However, in order to ensure we can maintain it, we display an ad from us with a 1% probability on your non-text inventory. We ensure that the ads we display are clean and safe for any environment. Contact us `contact at eas.rocks` if you have a problem with that.