~AR Posted December 11, 2013 Report Posted December 11, 2013 Hello, Looking for a way to asychronously run the invocation code to prevent ad loading from delaying page load times. I had looked into it previously, but ran into a roadblock because of the way the original OpenX call is structured. I believe it had something to do with the 'document.write' command IIRC. (It has been almost a year since I reviewed working around the problem, so I may be off.) Our company sites have a high saturation of ads all hosted on our servers (no third-party ads) and load times at times really slow the page down. If anyone can build this feature out, that would be tremendously helpful! And if you can code it for a Wordpress Widget plugin (possibly based off the OpenX-WP Widget) that would be even better! Quote
Erik Geurts Posted December 11, 2013 Report Posted December 11, 2013 The most important reason why asynchronous loading is complicated, is that many browsers fail to correctly process and display ads that are in turn third party ad tags. Because of this, I believe nobody has been able yet to build anything that works flawlesly. Quote
Ilya Ber Posted December 11, 2013 Report Posted December 11, 2013 I concur, however if you are not too much concerned with the 3rd party ads, I would recommend using https://code.google.com/p/jquery-lazyload-ad/ Quote
Guest Posted December 11, 2013 Report Posted December 11, 2013 You can use Single Page Invocation code to speed up page loads. but OpenX Wordpress Widget not support the Single Page Call . Quote
~AR Posted December 11, 2013 Author Report Posted December 11, 2013 thanks all! I had left off with looking into how to rewrite the invocation code to eliminate the 'document.write' command following the outline on the article here: http://www.stevesouders.com/blog/2012/04/10/dont-docwrite-scripts/ and http://www.stevesouders.com/blog/2010/12/15/controljs-part-3/ but being that this isn't my primary job, and that I'm mainly self-taught when it comes to javascript, I wasn't comfortable with putting it into practice. perhaps someone else can pick up the mantle? i've got to assume that creating a async version of the invocation code for an ad server would be highly beneficial. Especially since they are notoriously blamed for slow page load times, and almost entirely use the document.write statement which prevents/stops async loading of pages. ultimately, ads should be seemless on a page, not affecting load times. I know real-world case isn't going to be 100% non-interferance, but anything closer, I've got to imagine is going to be benificial and give an edge in the industry. Besides, isn't Revive all about reviving the ad server software world? Quote
davidm Posted January 7, 2014 Report Posted January 7, 2014 I got ads working async in 2011 via a lot of messy workarounds. I posted how I did it on the OX forums but I think it got buried under spam and whatever else is in there. It would be good to see Revive have a way to easily do async ad loading, but until that day comes, this is what worked for me: 1. You need to use the XMLRPC interface. So you need to copy the lib/xmlrpc/php/openads-xmlrpc.inc.php file to your website. 2. This method assumes you're using jQuery and have the migration plugin enabled, as it relies on $.browser.msie checks because it turns out IE can't handle using document.write on an iframe that is created dynamically (it'll write the content to the iframe, but it won't actually process it as being HTML content and just show everything as blank). So my workaround for that is the ad code for that impression is saved to memcache, then the iframe is set to a page that just loads the impression from memcache. A bit annoying but it works. 3. I'm also assuming you have memcached installed. You can write some sort of alternative thing that uses temporary files if you don't have memcache, but this was the simplest for me. 4. Have a line similar to this in your page: $(document).ready(function() { $.getScript("//websitegoeshere.com/includes/openx.php"); }); 5. The contents of openx.php are this (note that flat-out copypasta of this code will not work): <?php ob_start('ob_gzhandler'); set_time_limit(15); header('Content-Type: application/x-javascript'); // Set $server to the location of your ad server $server = 'adservergoeshere.com'; require(ROOT_DIR . '/includes/config.php'); require(ROOT_DIR . '/includes/functions.php'); require(ROOT_DIR . '/includes/openads-xmlrpc.inc.php'); if (!isset($OA_context)) $OA_context = array(); $oaXmlRpc = new OA_XmlRpc($server, '/www/delivery/axmlrpc.php', $_SERVER['HTTPS'] ? 443 : 80, $_SERVER['HTTPS'] ? true : false, 15); $openx = array(); $adzones = array( 'headerad' => 97, 'bodyad' => 98, 'boxtop' => 99, 'boxmiddle' => 106, 'boxbottom' => 100 ); foreach ($adzones as $key => $val) { $openx[$key] = $oaXmlRpc->view('zone:' . $val, 0, '', '', 0, $OA_context, 'UTF-8'); $OA_context[] = array('!=' => 'campaignid:' . $openx[$key]['campaignid']); } foreach ($openx as $key => &$val) { $val['html'] = str_replace('&', '&', $val['html']); $val['html'] = str_replace('&', '&', $val['html']); if ($val['aSearch'] && $val['aReplace']) { $val['html'] = str_replace($val['aSearch'], $val['aReplace'], $val['html']); $val['html'] = str_replace(str_replace(array('{', '}'), array('[', ']'), $val['aSearch']), $val['aReplace'], $val['html']); if (extension_loaded('memcache') && (preg_match('/MSIE|Internet Explorer/i', $_SERVER['HTTP_USER_AGENT'])) && (preg_match('/^<script/i', $val['html']))) { $uid = uniqid(); $val['uid'] = $uid; $memcache = getMemcache(); $memcache->set('tmpad:' . $uid, $val['html'], MEMCACHE_COMPRESSED, time() + 120); } } //if ($_SERVER['HTTPS']) $val['logUrl'] = preg_replace('/^http:\/\//', 'https://', $val['logUrl']); } echo 'var openx = ' . json_encode($openx) . ";\n"; ?> var oxserver = "http<?php if ($_SERVER['HTTPS']) echo 's'; ?>://<?php echo $server; ?>"; $(document).ready(function() { for (var z in openx) { var adbox = $("#" + z + ".adbox"); if ($(adbox).length) { var ad = openx[z]; ad['spot'] = z; if ((ad['html'].length) || (ad['contenttype'] == 'swf')) { var adcontent = $(adbox).children(); $(adbox).empty().append($("<div>").addClass("adnote").text("Advertisement")).append($("<div>").addClass("ad").append(adcontent)); if (ad['contenttype'] == 'swf') { drawFlashAd(ad); } else { if ((ad['html'].substr(0, 7) == "<scr"+"ipt") || (ad['html'].substr(0, 7) == "<SCR"+"IPT")) { drawIFrameAd(ad); } else { $(adbox).children(".ad").html(ad['html']); } } } else { $(adbox).css({display: "none"}); } } } }); function drawIFrameAd(ad) { var oxid = "ox_" + new Date().getTime(); var iframe = $("<iframe>").attr({name: oxid, id: oxid, width: ad['width'], height: ad['height'], frameborder: 0, scrolling: "no", vspace: 0, hspace: 0, marginheight: 0, marginwidth: 0}); var content = "<html><body>" + ad['html'] + "</body></html>"; if ($.browser.msie) $(iframe).attr({src: "/includes/adpage.php?ad=" + ad['uid']}); $("#" + ad['spot'] + " > .ad").append($(iframe)); if (!$.browser.msie) { var ifrm = $("#" + oxid).get(0); ifrm = (ifrm.contentWindow) ? ifrm.contentWindow : (ifrm.contentDocument.document) ? ifrm.contentDocument.document : ifrm.contentDocument; ifrm.document.open(); ifrm.document.write(content); ifrm.document.close(); } drawBeacon(oxid, ad); } function drawFlashAd(ad) { $.ajax({url: oxserver + "/www/delivery/fl.js", cache: true, dataType: "script", success: function() { var oxid = "ox_" + new Date().getTime(); var oxlink = $("<a>").attr({href: ad['clickUrl']}); var oximg = $("<img>").attr({src: ad['bannerContent'], width: ad['width'], height: ad['height'], alt: ad['alt'], title: ad['alt'], border: 0}); $("#" + ad['spot'] + " > .ad").append($("<div>").attr({id: oxid}).css({display: "inline"}).append($(oxlink).append($(oximg)))); var ox_swf = new FlashObject(oxserver + "/www/images/" + ad['aRow']['filename'], oxid, ad['width'], ad['height'], ad['aRow']['pluginversion']); var oxvars = /ox_swf\.addVariable\('([^']+)', '([^']+)'\);/g; var match; while (match = oxvars.exec(ad['html'])) { ox_swf.addVariable(match[1], match[2]); } ox_swf.addParam('allowScriptAccess','always'); ox_swf.addParam('wmode', 'opaque'); ox_swf.write(oxid); drawBeacon(oxid, ad); }}); } function drawBeacon(oxid, ad) { var beacon = $("<div>").attr({id: "beacon_" + oxid}).css({position: "absolute", left: "0px", top: "0px", visibility: "hidden"}); var bimg = $("<img>").attr({src: ad['logUrl'], width: 0, height: 0, alt: ""}).css({width: "0px", height: "0px"}); $("#" + ad['spot'] + " > .ad").append($(beacon).append($(bimg))); } The config.php and functions.php includes just contain my passwords/server details and a getMemcache function (which just returns a memcache object). ROOT_DIR is just a reference to $_SERVER['DOCUMENT_ROOT'] that is auto-appended to the start of my pages. The $adzones array is a list of zone IDs for your ads. The keys should be the IDs of the zones on the page (so on your page you should have <div class="adbox" id="keyname"></div> for each ad), and the values should be their corresponding ID numbers within Revive. You'll see that there's a reference to adpage.php - this is my alternate way of getting iframe ads to work in IE. The contents of adpage.php is this: <html><body><?php require(ROOT_DIR . '/includes/config.php'); require(ROOT_DIR . '/includes/functions.php'); $memcache = getMemcache(); $adid = $_GET['ad']; if (!preg_match('/^[0-9A-Za-z]+$/', $ad)) die(); $ad = $memcache->get('tmpad:' . $adid, MEMCACHE_COMPRESSED); $memcache->delete('tmpad:' . $adid); echo $ad; ?></body></html> This should give you async loading for image/Flash ads as well as third-party ones. We haven't used other ad types here so I don't know how they'll go with this. Quote
gabrielt Posted January 13, 2014 Report Posted January 13, 2014 +1. And thanks for the jquery-lazyload-ad link, I will take a look into that. Installed a Lazyload script for images, and needed something similar for the banners. Quote
xtech Posted January 26, 2014 Report Posted January 26, 2014 +2 Asynchronous loading would be the top #1 feature for me. It would be great not to have to code it all, but be included in revive ad server. Quote
bgrabkowitz Posted January 27, 2014 Report Posted January 27, 2014 Works flawlessly: http://quotefountain.com/ Iframes are your friend. We load all content including spcjs calls in iframes and then transfer results back to main document. Quote
middir Posted February 13, 2014 Report Posted February 13, 2014 bgrabkowitz, yes iframe works fine, but brings some issue with expand tags, the best will be a native way to have asynchronous way to show any tag, it seems that the guys from openx managed to do it : http://docs.openx.com/ad_server/adtagguide_asynchjs.html I tried DFP async option, but it's not suitable as it seems that the just work around the issue and create an iframe with their async tag and the issue of the expand tag happen too. I am not sure if it's do-able, but as Google is now ranking site depending on their speed too, I guess this kind of option will be more and more asked by publishers. Wanted to share my experience and open the discussion to see what is faisable around this point. Cheers, Quote
xtech Posted February 13, 2014 Report Posted February 13, 2014 Totally agree. I think async loading should be a top priority for Revive Adserver. Quote
wt759 Posted February 17, 2014 Report Posted February 17, 2014 +1 for implementing async loading I have tried jquery-lazyload-ad (http://jqueryad.web2ajax.fr/). Works fine for the most scenarios, but not if you use the Invocation Code from another openX Server. Thomas Quote
xtech Posted February 19, 2014 Report Posted February 19, 2014 I think we could ask the moderation to move this topic to the "feature request" forum as it seems to be a quite popular feature request. Quote
Crazy-Achmet Posted March 10, 2014 Report Posted March 10, 2014 Same here! Asynchronous loading would be the number 1 killer feature for revive! Btw. here is a asynchronous jquery plugin for OpenX, maybe someone can make adjustments so it will work with Revive? http://blog.denivip.ru/index.php/2011/07/jquery-openxtag-en/?lang=en Quote
Alex de Borba Posted April 7, 2014 Report Posted April 7, 2014 +1. And thanks for the jquery-lazyload-ad link, I will take a look into that. Installed a Lazyload script for images, and needed something similar for the banners. In another post you said you have CloudFlare, if so, they do that Lazyload already as an option, however, not sure if you know but with CloudFlare enabled and Lazyload hosted IN your server, the AdServer will be come even more slow. Quote
scott001 Posted April 9, 2014 Report Posted April 9, 2014 davidm, would you mind clarifying this part of your post? The config.php and functions.php includes just contain my passwords/server details and a getMemcache function (which just returns a memcache object). Ideally could you post samples of your config.php and functions.php files? Quote
andrewatfornax Posted April 24, 2014 Report Posted April 24, 2014 Asynchronous loading would be the top #1 feature for me. It would be great not to have to code it all, but be included in revive ad server. Happy to accept pull requests on GitHub! Quote
nattila Posted May 6, 2014 Report Posted May 6, 2014 Totally agree. I think async loading wolud be a nice feature. Quote
delete-me Posted May 7, 2014 Report Posted May 7, 2014 Since I've taken the time to find a solution which works for my website, I decided to pass along my solution. This works in a jQuery environment, but doesn't depend on jQuery. Using this Javascript library (available under the terms of the MIT License): https://github.com/iamnoah/writeCapture/tree/writeCapture2 First, load the library, so you can use the function: <script src="/path/to/element.write.js"></script> <script src="/path/to/writeCapture2.js"></script> Then simply rewrite your invocation code like so <div id="AdPlaceholder"> <!-- ad will go here --> </div> <script> /* this function wrapper keeps global memory space clear of random variables */ (function(){ var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:") + "//example.com/ReviveAdserver/www/delivery/ajs.php" + "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999) + "&charset=UTF-8&loc=" + encodeURIComponent(window.location) + (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "") + (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "") + (document.context ? ("&context=" + encodeURIComponent(document.context)) : "") + (document.mmm_fo ? "&mmm_fo=1" : ""); writeCapture.write( document.getElementById("AdPlaceholder"), "<scr" + "ipt src='" + oxSrc + "'></scr" + "ipt>" ); })(); </script> If you don't need the ability to prevent displaying the same banner / campaign / advertiser on a single page, then you are done. If your like me, and need campaign and advertiser blocking (to prevent duplicates), you'll have to do continue with the next step. When the javascript runs the string stored in oxSrc has the current value of document.context, however subsequent ads need the revised value of document.context, to prevent duplicate ads. The solution is to wrap the string creation into the javascript which is excuted asynchronously, so that the revised value of document.context is used, like so <div id="AdPlaceholder"> <!-- ad will go here --> </div> <script> /* this function wrapper keeps global memory space clear of random variables */ (function(){ writeCapture.write( document.getElementById("AdPlaceholder"), '<scr' + 'ipt>' + 'var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:")' + '+ "//example.com/ReviveAdserver/www/delivery/ajs.php"' + '+ "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999)' + '+ "&charset=UTF-8&loc=" + encodeURIComponent(window.location)' + '+ (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "")' + '+ (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "")' + '+ (document.context ? ("&context=" + encodeURIComponent(document.context)) : "")' + '+ (document.mmm_fo ? "&mmm_fo=1" : "");' + 'document.write("<scr" + "ipt src=\'" + oxSrc + "\'></scr" + "ipt>");' + '</scr' + 'ipt>' ); })(); </script> Yes, this is quite ugly code, and you'll have to be careful when editing it, as it's javascript which writes javascript. I hope this is able to help people, until Revive Adserver offers a direct solution to display ads asynchronously. andrewatfornax 1 Quote
nattila Posted May 11, 2014 Report Posted May 11, 2014 What about Google Tag Manager? TM support document.write() method as I can see. Would it be possible to use TM for adserver invocation code? Quote
redstorm Posted June 1, 2014 Report Posted June 1, 2014 Since I've taken the time to find a solution which works for my website, I decided to pass along my solution. This works in a jQuery environment, but doesn't depend on jQuery. Using this Javascript library (available under the terms of the MIT License): https://github.com/iamnoah/writeCapture/tree/writeCapture2 First, load the library, so you can use the function: <script src="/path/to/element.write.js"></script> <script src="/path/to/writeCapture2.js"></script> Then simply rewrite your invocation code like so <div id="AdPlaceholder"> <!-- ad will go here --> </div> <script> /* this function wrapper keeps global memory space clear of random variables */ (function(){ var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:") + "//example.com/ReviveAdserver/www/delivery/ajs.php" + "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999) + "&charset=UTF-8&loc=" + encodeURIComponent(window.location) + (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "") + (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "") + (document.context ? ("&context=" + encodeURIComponent(document.context)) : "") + (document.mmm_fo ? "&mmm_fo=1" : ""); writeCapture.write( document.getElementById("AdPlaceholder"), "<scr" + "ipt src='" + oxSrc + "'></scr" + "ipt>" ); })(); </script> If you don't need the ability to prevent displaying the same banner / campaign / advertiser on a single page, then you are done. If your like me, and need campaign and advertiser blocking (to prevent duplicates), you'll have to do continue with the next step. When the javascript runs the string stored in oxSrc has the current value of document.context, however subsequent ads need the revised value of document.context, to prevent duplicate ads. The solution is to wrap the string creation into the javascript which is excuted asynchronously, so that the revised value of document.context is used, like so <div id="AdPlaceholder"> <!-- ad will go here --> </div> <script> /* this function wrapper keeps global memory space clear of random variables */ (function(){ writeCapture.write( document.getElementById("AdPlaceholder"), '<scr' + 'ipt>' + 'var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:")' + '+ "//example.com/ReviveAdserver/www/delivery/ajs.php"' + '+ "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999)' + '+ "&charset=UTF-8&loc=" + encodeURIComponent(window.location)' + '+ (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "")' + '+ (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "")' + '+ (document.context ? ("&context=" + encodeURIComponent(document.context)) : "")' + '+ (document.mmm_fo ? "&mmm_fo=1" : "");' + 'document.write("<scr" + "ipt src=\'" + oxSrc + "\'></scr" + "ipt>");' + '</scr' + 'ipt>' ); Yes, this is quite ugly code, and you'll have to be careful when editing it, as it's javascript which writes javascript. I hope this is able to help people, until Revive Adserver offers a direct solution to display ads asynchronously. digitaladapt could you post the example code of how you are calling this code. Thanks ReferenceError: data is not defined parent.appendChild(el); writeCapture2.js (line 260) Quote
andrewatfornax Posted June 2, 2014 Report Posted June 2, 2014 Well, async loading is clearly a hot topic, so it's something to really think about for me in terms of perhaps including it on the roadmap. Just for my own sanity, though - given the complexity of async loading, and as Erik has mentioned, the risks it introduces in terms of cross-browser compatibility - why is it so important to you all (i.e. those +1ing above)? Why would async loading be any better than, say, putting your standard JS tags at the bottom of the page with appropriate CSS to position them? Is it just that this approach is too complex for most people to cope with, and you'd all rather have something that might not always work, but is less effort to think about in terms of just being able to drop into the site where you need the ads? Or am I missing something else? Thanks. Quote
redstorm Posted June 2, 2014 Report Posted June 2, 2014 The main theme for wanting async loading of ad's is to increase page load speed, and not have the ad's block the loading of the main content. With google now rating the site on speed + content now slow page loads will kill google page rateings. Ive worked around my issue for now with using the iframe code and using jquery.load to call the ad iframe. Quote
~AR Posted June 2, 2014 Author Report Posted June 2, 2014 Well, async loading is clearly a hot topic, so it's something to really think about for me in terms of perhaps including it on the roadmap. Just for my own sanity, though - given the complexity of async loading, and as Erik has mentioned, the risks it introduces in terms of cross-browser compatibility - why is it so important to you all (i.e. those +1ing above)? Why would async loading be any better than, say, putting your standard JS tags at the bottom of the page with appropriate CSS to position them? Is it just that this approach is too complex for most people to cope with, and you'd all rather have something that might not always work, but is less effort to think about in terms of just being able to drop into the site where you need the ads? Or am I missing something else? Thanks. Thanks Andrew for your reply. As the starter of, what has become a wildfire of a thread here, I thought I'd chime in. I've been monitoring the progress of this thread since I posted it and I still believe Asynchronous loading should be a top priority and is vital to speeding page load speeds. And if Revive wants to be at the forefront of ad servers (which it should be), it needs to be built in. As Redstorm stated above, page rankings are severely affected by page load times. Yes, coders have always been able to modify, work-around or adapt, as some suggestions have been posted (which by the way are great work in the right direction), but ultimately, universal usability is going to be the Revive strong point. Create something that doesn't get in the way of the design and usability (non-asyc currently does just that) and your market for developers has then opened up to nearly anyone looking for a competent alternative. I can't stand Google DFP, OpenX is a joke (don't even get me started), and what are you really left with? Revive has a chance to become the Unix/Unbuntu of the ad server world, but maintaining universality will be key in keeping the project at the top of the list. I have been using OX, OAds, etc since it was still PHPads (can't recall what generation it was when I first started using it, but since early 2000s) and believe, it has the potential to be a far better ad server over the "services" provided out there. Sans the monetized atrocity that OpenX became, OpenAds/Revive has always been about being the ad server that WORKS for those that don't want to use the alternative "services" out there. No site admin wants to research, rewrite, or modify the invocation codes, they simply want to put it in place and manage inventory, and not have to be concerned that their "workaround" may break or degenerate to an unusable state, because the software is updated or changed. Make it work, make it work right, keep it transparent within a site, and make it so ANYONE can use it. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.