Skip to content

Commit

Permalink
first
Browse files Browse the repository at this point in the history
  • Loading branch information
djlosch committed Sep 28, 2015
0 parents commit 5fa80c7
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 0 deletions.
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
## What is Apollo?

If you're getting adblocked, you should know what the impact is. Apollo is an adblock detector that you embed on your pages and use to measure the percentage of your userbase using Alock.

## How does it work / What method does Apollo use?

Adblockers use filter matching -- they check element ids and classes. If there's a match, the adblocker reduces the element height to zero, or removes it from the page entirely. If you know the div should be there (or be a certain height), but it's not, then the visitor probably has adblock enabled.

By default, Apollo attempts to log the adblock detector results to your [Google Analytics](http://www.google.com/analytics/) (GA) profile. You can use universal analytics (analytics.js) which uses `ga()`, or either legacy implementations from ga.js (`trackEvent()` and `_gaq.push()`).

Apollo is not endorsed by, supported by, or related in any way to Google or Google Analytics.

## What's the license on Apollo?

[MIT](https://en.wikipedia.org/wiki/MIT_License). Pull requests and courtesy beer are encouraged but not required.

## How do I test this out and set it up?

**Step 1**: Make sure you have GA set up on your page.

**Step 2**: Embed the javascript tag in your HTML, somewhere near or in your footer, preferably as the last thing on the page before your `</footer>` or `</body>` tag:

<script src="//djlosch.github.io/apollo/apollo.js?verbose=true"></script>

**Step 3**: Load the page you included this tag on in your browser. Open the javascript console (in most browsers, right click, select "Inspect Element" and then click the Console tab) and refresh. Since you added the tag with `verbose=true`, you should see diagnostic output in the console.

**Step 4**: Customize the options to your use case. All of these have default settings.

* `id (string)` : you can mod Apollo to use a known ad unit on your page. Do not include the hash sign. If you do not specify an id, Apollo will add a 300x250 empty div offpage, which is confirmed to be adblocked by popular filters, and then test whether the div is blocked for the visitor.

* `sampling (int)` : percentage of pageviews Apollo should test adblocking. By default, Apollo tests every pageview. For high-traffic sites, this can really pollute your Google Analytics profile. Unless you've upgraded to a premium package, the number of datapoints you get per day can easily get blown out by event tracking. Larger sites will frequently want to drop this down to 10 or lower. DO NOT include a percent sign.

* `verbose (bool)` : whether you want diagnostic info to be displayed. When you push this code live, you should have verbose turned off.

* `timeout (int)` : time to wait before testing any adblocking, in milliseconds. Some setups lazy load ad divs and/or GA. The timeout should usually be nonzero because even if you rush to load GA, it's not always immediately loaded before the visitor loads Apollo. By default, the timeout is 100ms.

* `categoryBlocked (string)` : is the GA category that Apollo will submit when adblocking is confirmed. By default, this is set to `adblock (apollo)`.

* `categoryUnblocked (string)` : is the GA category that Apollo will submit when no adblocking is confirmed. By default, this is also set to `adblock (apollo)` (the same as the blocked category) so that you can easily look up all adblocking in a single category.

* `actionBlocked (string)` : is the GA action that Apollo will submit when adblocking is confirmed. By default, this is set to `blocked`.

* `actionUnblocked (string)` : is the GA action that Apollo will submit when no adblocking is confirmed. By default, this is set to `unblocked`.

* `labelBlocked (string)` : is the GA label that Apollo will submit when adblocking is confirmed. By default, this is set to the path of the current page (`window.location.pathname`)

* `labelUnblocked (string)` : is the GA label that Apollo will submit when no adblocking is confirmed. By default, this is set to the path of the current page (`window.location.pathname`)

## Examples

Test on 100% of pageviews, using a timeout of 100ms, using Apollo's default div.

<script src="//djlosch.github.io/apollo/apollo.js"></script>

Sample 50% of pageviews, on a div with `id="right-med-rec"`, with a timeout of 200ms.

<script src="//djlosch.github.io/apollo/apollo.js?id=right-med-rec&timeout=200&sampling=50"></script>

Sample 10% of pageviews, on a div with `id="leaderboard"`, with a timeout of 50ms, modifying the GA actions to `leaderboard-blocked` and `leaderboard-unblocked` when the unit is blocked/unblocked respectively.

<script src="//djlosch.github.io/apollo/apollo.js?id=leaderboard&timeout=50&sampling=10&actionBlocked=leadboard-blocked&actionUnblocked=leaderboard-unblocked"></script>

## Can I modify Apollo to block / redirect / maim users of adblock software?

Functionally, yes, because Apollo tests individual visitors' usage of adblock, you can tell exactly which users are using adblock.

The question is really *whether* you should terrorize them. Before you do that, consider this: two major German publishers sued the largest adblock company. Not only did the publishers lose their lawsuit, the news coverage exposed the technology to a lot of people who didn't previously know about adblocking. This drove the adblocking rate up in Germany. Way up. Adblock usage varies by country and site audience, but the nationwide estimates for general audiences in most of the western world usually run 5-20%. After this lawsuit, general audience adblock rates in Germany are as high as 40%+.

Instead of terrorizing them, please consider alternate monetization strategies. You'll want to add your logic to lines 154 and 152.

## Can I self-host or rename apollo.js?

Yes, you can, but if you do rename it, make sure you search the source and modify `scriptName` to match your filename. The filename is used to import your config from its `$_GET` variables.
161 changes: 161 additions & 0 deletions apollo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
Copyright (c) 2015 David Loschiavo, zerodarknerdy.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var APOLLO = APOLLO || (function() {
var scriptName = 'apollo.js';
var defaultID = 'apollo_adblock_placeholder';
var analytics = {};
var _args = {
'id' : defaultID,
'sampling' : 100, // percentage of pageviews that we'll test for adblocking
'verbose' : false, // do you want extra messaging to appear in console.log?
'timeout' : 100, // ms to wait before checking for ad blocking
'categoryBlocked' : 'adblock (apollo)', // GA category to be used when adblocking is detected
'categoryUnblocked' : 'adblock (apollo)', // GA category to be used when adblocking is NOT detected
'actionBlocked' : 'blocked', // GA action to be used when adblocking is detected
'actionUnblocked' : 'unblocked', // GA action to be used when adblocking is NOT detected
'labelBlocked' : window.location.pathname, // GA label to be used when adblocking is detected
'labelUnblocked' : window.location.pathname, // GA label to be used when adblocking is NOT detected
};

return {
init : function() {
// import args
var scripts = document.getElementsByTagName("script");
var i, j, src, parts, basePath;
var found = false;
for (i = 0; i < scripts.length; i++) {
src = scripts[i].src;
if (src.indexOf(scriptName) != -1) {
found = true;
parts = src.split('?');
basePath = parts[0].replace(scriptName, '');
if (parts[1]) {
var opt = parts[1].split('&');
for (j = opt.length-1; j >= 0; --j) {
var pair = opt[j].split('=');
_args[pair[0]] = pair[1];
}
}
break;
}
}
if (!found) {
console.log('adblocking analytics script has been renamed, and arguments are not detectable. please make sure you update "scriptName" in the source');
}

// sampling is off by default, but for high traffic sites, you may want to drop this down below 20 or you will hit daily datapoint limits in
if (_args.sampling < 100) {
var random = Math.floor((Math.random() * 100) + 1);
if (random > _args.sampling) {
_args.test = false;
if (_args.verbose)
console.log('skipping adblock test / sampling[' + _args.sampling + '%] rolled[' + random + ']');
return false;
}
}

if (_args.id == defaultID) {
if (_args.verbose)
console.log('using placeholder id[' + defaultID + ']');
document.body.innerHTML += '<div class="advertisement ad advertising ad_holder" id="' + defaultID + '" style="width:300px;height:250px;background:#CCC;top:-500px;position:absolute;"></div>';
} else {
if (_args.verbose)
console.log('not using placeholder id[' + defaultID + ']');
}

return true;
},
hasGoogleAnalyticsSupport : function() {
// ga() tracking in analytics.js... see https://developers.google.com/analytics/devguides/collection/analyticsjs/events
analytics.ga = true;
if (typeof window.ga != 'function') {
analytics.ga = false;
}
if (_args.verbose)
console.log('GA support via ga()[' + analytics.ga + ']');

// trackEvent tracking in ga.js... see https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide?hl=en
analytics.trackEvent = true;
if (typeof window.trackEvent != 'function') {
analytics.trackEvent = false;
}
if (_args.verbose)
console.log('GA support via trackEvent()[' + analytics.trackEvent + ']');

// some ultra-legacy implementations using ga.js weren't set up to use trackEvent() and need to gaq.push() instead.
analytics.gaq = true;
if (typeof _gaq == 'undefined') {
analytics.gaq = false;
}
if (_args.verbose)
console.log('GA support via _gaq[' + analytics.gaq + ']');

if (!analytics.ga && !analytics.trackEvent && !analytics.gaq) {
if (_args.verbose)
console.log('GA tracking is not available');
return false;
}
return true;
},
adblocked : function() {
if (_args.verbose)
console.log('starting adblock test');
var tag = document.getElementById(_args.id);
if ((tag.length < 1) || (tag.clientHeight < 1)) {
if (_args.verbose)
console.log('adblock on');
return true;
}
if (_args.verbose)
console.log('adblock off');
return false;
},
logToGoogleAnalytics : function(category, action, label) {
if (analytics.ga) {
ga('send', 'event', category, action, label);
} else if (analytics.trackEvent) {
trackEvent(category, action, label);
} else if (analytics.gaq) {
_gaq.push(['_trackEvent', category, action, label]);
}
},
getCategoryBlocked : function() { return _args.categoryBlocked; },
getActionBlocked : function() { return _args.actionBlocked; },
getLabelBlocked : function() { return _args.labelBlocked; },
getCategoryUnblocked : function() { return _args.categoryUnblocked; },
getActionUnblocked : function() { return _args.actionUnblocked; },
getLabelUnblocked : function() { return _args.labelUnblocked; },
}
}());

if (APOLLO.init()) {
setTimeout(function() {
if (APOLLO.hasGoogleAnalyticsSupport()) {
if (APOLLO.adblocked()) {
APOLLO.logToGoogleAnalytics(APOLLO.getCategoryBlocked(), APOLLO.getActionBlocked(), APOLLO.getLabelBlocked());
} else {
APOLLO.logToGoogleAnalytics(APOLLO.getCategoryUnblocked(), APOLLO.getActionUnblocked(), APOLLO.getLabelUnblocked());
}
}
}, APOLLO.timeout);
}

0 comments on commit 5fa80c7

Please sign in to comment.