Ads are broken: Error: "this.log is not a function"

adtech

#1

Just installed sovrn ads, this is the result:

this.log is not a function

Ads don’t show up, this is in Chrome’s developer tools:
image

After formatting the JS code in developer tools, it’s line 237 in fpi.js that’s not working:

return this.log("element does not exist"),

What element is missing? I copied the code exactly as it was on your platform.

I started manually reversing your code. The error is thrown because the following element does not exist:

document.getElementById(x.ad_unit_id)

and I’ve reconstructed the object x by manually stepping through your functions:

{"qs":"z=503197&width=320&height=50","fp_params":{"z":"503197","width":"320","height":"50"},"ad_unit_id":"sovrn_ad_unit_503197_async"}

where qs is the part of the script URL that automatically gets retrieved from the script tag:

<script src="//ap.lijit.com/www/delivery/fpi.js?z=503197&amp;width=320&amp;height=50"></script>

My first guess is that your script can’t handle the ampersands & that were auto-converted to &amp; by the browser. The values of x, qs and fp_params I showed above are the ones I got by doing it manually (in which case the URL string contained & rather than &amp;).

It’s definitely possible, considering your script is hard-coded for &:

g = a.split("&"),

and stepping through your code manually with links containing &amp; breaks the script.

In any case, this should help you figure something out.

Thoughts?


#2

Hi @sebastienvercammen,

Thanks for sending this information our way!

Often times these TypeErrors originate from a typo in the function name, as you indicated in your response. The ampersands should not necessarily cause an issue either.

We do not recommend reconstructing the ad tags as this can hinder their functionality and overall performance. I would recommend reimplementing the tag straight from your Meridian account. I can also send you a txt file with the script if you would prefer. I am happy to take a closer look at your page if you would like to reach out directly at publishersupport@sovrn.com with your domain and username.

Best,
Anna


#3

Hi @acarpinello,

The code I’ve implemented is unedited, it’s a simple line of code that includes sovrn ads as a script tag by constructing it and appending it to the DOM (done to select ad size based on screen size, since you have no responsive ads):

        function includeScriptFromURL(adEl, source) {
            var x = document.createElement('script');
            x.src = source;
            adEl.appendChild(x);
        }

        var ad = document.getElementById('sovrnad');
        includeScriptFromURL(adEl, '//ap.lijit.com/www/delivery/fpi.js?z=502436&width=728&height=90');

Done this way, & automatically gets converted to &amp; in the DOM by the browser.

I promise you, nothing is “reconstructed”, and you can save me the speech of “it will affect functionality and performance”. I’m a full stack developer and software engineer. I only started reversing your code back into readable functions because your script, unedited, by itself, throws errors and does not work.

If you’d like, I can finish reconstructing your code and implement a fix myself, but I believe this isn’t in your or my interest (I sincerely don’t wish to waste more time on this).


#5

Hi @sebastienvercammen,

Below is an optional solution to your code but, as the tags are not built to operate in this way, we do not recommend it as best practice. I suggest trafficking the tags through an adserver, like DFP, and allowing them to compete for the same zone, thus creating the responsive unit you are looking for while increasing CPM’s and overall yield.

<script type="text/javascript">
    var browserWidth = window.innerWidth && document.documentElement.clientWidth ? Math.min(window.innerWidth, document.documentElement.clientWidth) : window.innerWidth || document.documentElement.clientWidth || document.getElementsByTagName("body")[0].clientWidth;
    const phone_breakpoint = 768;
    const tablet_breakpoint = 1024;
    const bp = phone_breakpoint;
    if (browserWidth < bp) {
        document.write('<script src="//ap.lijit.com/www/delivery/fpi.js?z=503197&amp;width=320&amp;height=50"></script>')
    } else {
        document.write('<script src="//ap.lijit.com/www/delivery/fpi.js?z=503197&amp;width=320&amp;height=50"></script>')
    };
    </script>

Hope this helps.

Best,
Anna


#6

Hi @acarpinello,

While I understand that you believed your example would work because document.write is writing serialized text and doesn’t evaluate the URL to its safely encoded value with &amp;, this approach should not be recommended because document.write is bad practice (and you would have to replace &amp; in your example with &).

On top of not being recommended, your example will also break your website, since you are using document.write to write the following result:

<script type="text/javascript">
    var browserWidth = window.innerWidth && document.documentElement.clientWidth ? Math.min(window.innerWidth, document.documentElement.clientWidth) : window.innerWidth || document.documentElement.clientWidth || document.getElementsByTagName("body")[0].clientWidth;
    const phone_breakpoint = 768;
    const tablet_breakpoint = 1024;
    const bp = phone_breakpoint;
    <script src="//ap.lijit.com/www/delivery/fpi.js?z=503197&amp;width=320&amp;height=50"></script>
</script>

which will not work, because you can’t have a script tag inside of a script tag, and the closing tag you just wrote would have closed your initial script tag and rendered all following JavaScript useless (rendered as simple text).

Instead, consider telling your tech people to take a look at this thread and implement the fix I suggested to allow evaluated URLs, which would allow the following approach with proper DOM manipulation:

    <div id="sovrnad"></div>
    <script type="text/javascript">
    (function() {
        function includeScriptFromURL(adEl, source) {
            var x = document.createElement('script');
            x.src = source;
            adEl.appendChild(x);
        }

        function doStuff() {
            /* Calculate the width of available ad space */
            var adEl = document.getElementById('sovrnad');

            var adWidth = 320;
            if (adEl && adEl.getBoundingClientRect().width) {
                adWidth = adEl.getBoundingClientRect().width; // Modern browsers.
            } else if (adEl) {
                adWidth = ad.offsetWidth; // Old IE.
            }

            // Load ad.
            if (adWidth >= 728) {
                includeScriptFromURL(adEl, '//ap.lijit.com/www/delivery/fpi.js?z=502436&width=728&height=90');
            } else if (adWidth >= 468) {
                includeScriptFromURL(adEl, '//ap.lijit.com/www/delivery/fpi.js?z=503196&width=468&height=60');
            } else {
                includeScriptFromURL(adEl, '//ap.lijit.com/www/delivery/fpi.js?z=503197&width=320&height=50');
            }
        }
    })();
    </script>

Adjustable for any number of viewports, uses the available size for the container rather than the window or document, and can easily be improved to use a list of ad sizes and scripts rather than the simple but ugly list of conditionals I’ve used in my example.

Please get someone to listen to my advice. I’m not giving it without reason.


#7

Hi @sebastienvercammen,

Thanks for taking interest in our tech, and offering this advice!

While we appreciate you looking into the issue, it is not something that makes business sense to build out the solution for. A vast majority of our publishers that require the functionality you are desiring make use of ad servers to serve responsive ad units, DFP being by far the most popular.

While the solution that @acarpinello has provided is not best practice, it is the best way we know of to do what you are wanting without an Ad Server.

Please don’t hesitate if you discover an alternative, or have any other questions about our products!

Thanks,
Ted Rand


#8

Hi @Ted_Rand,

It isn’t just bad practice, I also explained why the code itself would not work: a <script> tag inside of another script tag is invalid HTML and will break the script tag structure, ending the primary block prematurely.

There is also nothing to “build”: a potential fix to this problem is a single line of code that needs to be changed, and your ad serving code will only continue to work as long as you don’t use any kind of code that gets evaluated into its safe representation by any browser (which automatically converts & to &amp; because it’s 2017 and browsers have caught up and have implemented proper standards).

I know of several alternatives, but all are bad practice and unsupported techniques that might break in the future when browsers fix these “side tricks” to bypass the proper standards.

I’m alarmed that an ad serving network doesn’t even understand or implement proper browser standards. If anything is your responsibility, I believe it would be to make sure you understand cross-browser compatibility and standards so your ads actually get served. If you’re skipping out on changing a single line of code to implement proper standards, what else are you skipping out on?

I first thought on adding an example of the bad practice alternatives in this comment, but I’m convinced you would take that code and start recommending it to your publishers to avoid having to work on an actual fix because you would see it as a “solution”.


#9

Hi @sebastienvercammen,

We appreciate the insight and will have some of our senior software engineers read this thread to take your suggestions into closer consideration. If the above recommendations do not meet your trafficking requirements, we completely understand and a partnership with Sovrn may not be the best solution for your site at this time. You are also welcome to reach out directly at publishersupport@sovrn.com with any further questions or concerns.

Best,
Anna