Many years have passed since the first time Javascript entered our web pages, turning them from static forms into the dynamic, vivid creatures they are today. Every year, the amount of scripts, styles, and plugins in every popular site keeps increasing. Inevitably, you cannot expect the site maintainers to develop everything they need on their own.
Consequently, they come to rely on external content, tools, plugins, and services to handle many of their growing needs, like buttons, comment sections, ads, chatbots, and more. These tools, usually generalized and used by many different consumer sites, are all 3rd party services.
At Taboola, such 3rd party services are a critical part of our product. Namely Rbox, our recommendation product, is a 3rd party service embedded in publisher sites. A dedicated team of top skill front-end developers and web experts are responsible for developing and maintaining the Rbox. Supporting the Rbox is a hard, complicated job, but a rewarding one.
When we observe the differences between writing a 3rd party service to writing for the host application, we can find many points of interest:
Feature/Platform | Host | 3rd Party |
CORS conflicts | Usually same origin site and content, so no problems. | Can face problems trying to get resources from another source. |
Main window control | Can access whatever variables and API’s they want, no objections (unless no browser support). | May face clashes with global variables, clash with host API usage, sometimes living in an iframe. |
Web resource usage | Can use as much network bandwidth as they like, whatever libraries they want (as long as their customers live with that). | Better not bring too much code and use too much network at the expanse of their host. |
Content positioning | Always aware of where their content is relative to the page. | May be placed at every point (may change due to agreements between the 2 sides) and must adjust to every circumstance. |
Security and compatibility | Security very important for company and client interests. Host code should strive to be safe from security breaches, malformed code, and compromised dependencies. | Security is even more crucial. In 3rd party scripting, there’s no such thing as “too much” security, since 3rd parties act on someone else’s site. If there is any doubt about using certain libraries or code aspects, the default answer is “don’t” until proven otherwise. |
AMP | Can use whatever AMP components they want and add the amp-scripts they want. | Need host consent in order to bring the components they need, have limited availability to the page. |
Performance | Even though the host can suffer from performance issues, it does not always address them. This may be because there is not enough impact, more focus on making content, or no fitting tools to find the problem. | Must monitor all traffic and identify performance constantly since host sites can see which 3rd party services cause issues and need to be able to shut them down. Most challenging to 3rd party providers is the fact that most of the scripts are generic across all of the hosts, and those scripts might expose different performance impacts on specific types of traffic. |
As the writers of a 3rd party script, we cannot enjoy the advantages of using whatever we want, knowing everything we need, and having access to everything a page offers. Worse, since we may “live” in many different sites, each with their own styling, privacy conventions, and state of global javascript context, we need to adapt to every possible situation, sometimes even surreal ones.
Let’s go over some of the more potent and common challenges and see how we at Taboola handle them:
This seat is already taken, sir
Imagine you’re working on your code. You’re toiling endlessly on polishing every bit, ousting every bug, solving any edge case, brandishing every feature, just to have everything crash and burn the moment your script is uploaded on the client’s site. And for what reason? Because you wrote something like this:
// myAwesome3rdParty.js
And it just so happens that the host site has a script that looks like this:
// HostCode.js
And guess what happens? An exception is thrown on your side, and things break (or worse, an exception is thrown on their side and host site breaks), and next thing you know, your customer is on the phone and is furious because you stepped on their toes.
So, what can we, as good citizens, do to avoid this chaos:
- Namespacing: First, it is beneficial to have our variables with their own prefixes to reduce naming clashes. Most coders use descriptive names for their variables, and they usually wouldn’t use our unique prefixes in their variables. This way, we greatly reduce the harm potential
- Encapsulate into private “modules”: namespacing is easy and fast, but not absolute. Being implemented in so many sites, you can never know what someone may do to alter them.
Hence, it is imperative to have our code as isolated as possible. Have all our variables hidden inside code blocks, functions, and modules (which in classic vanilla javascript, would look like this):
In the example above, any declared variable will only be visible to this secluded scope and will not clash with the host code scope.Unless someone does something careless…
Who moved my API?
Do you think overriding someone’s variable is bad? Imagine what happens when you override a webpage API. So, let’s imagine you would like to use an API like IntersectionObserver in order to know when certain elements are in the viewport. IntersectionObserver is a native API, so you don’t even need to import it from anywhere!
And yet, it is not supported on IE, so a bit of caution is necessary. You decide to go with this approach:
window.IntersectionObserver = window.IntersectionObserver || myintersctionObserverPolyfill;
Seems legit, right? In case the browser supports IntersectionObserver, you will use native implementation. If not, you can have your own polyfill, and everything’s fine, correct?
But, what if you’re not the only one who thought about this? What if the host code does just this:
window.IntersectionObserver = window.IntersectionObserver || theirIntersctionObserverPolyfill;
This means that either you’re going to use their polyfill, or they will use yours in any browser that does not support native. Since there may be various versions to even native APIs, things can get tricky.And this is just one example. Caution is needed when doing something like overriding anything that sits on ‘window.’ A better method would be:
const myintersectionObserver = window.IntersectionObserver || myintersctionObserverPolyfill
And use myintersectionObserver in your code instead. One must be careful when changing something that the host site may employ. This is also true to external library clashes, prototype overrides, and more.
Floating red boxes are a tradition here
Ok, so you were careful. You put every variable, every class, every style in isolation. You know your code and the customer’s code live in parallel universes. There shouldn’t be any problems now, right? They’ll do their thing, and you do yours, and you’ll all live happily ever after, until…
But how??? We have no similar classes. We made sure to get everything specified to the max.Alas, CSS doesn’t care. Consider the following code segments:
// myAwesome3rdParty.css
And their code:
// HostStyle.css
What a mess! These are some predatory rules, and they might work fine for the host since they built everything around it. But it sure doesn’t work right for you. Worse, you may think to get your styles hyper specified, something like:
here is the code:
This may be useful in some cases, but then they hit you with the worst offender of all:
!important
Which nothing can beat.
Is there a solution?
One of our basic solutions for publishers is custom CSS hooks, which means that we can add additional style rules in order to reconcile the gaps between us and a specific publisher . We can use higher specificity rules, change the way we uphold our styles, and in some rare cases, even use an !important or two just to set things right. Using these should be very subtle, but it allows a generic service to be more user-tailored.
Live in the pod (and eat the bugs)
There are many types of 3rd party services. Some of them as simple as showing a small ad, a little panel with some content, a button that sends ajax, or even a nice slideshow.
But some 3rd party services can get very complicated. Taboola, in particular, offers some features that may count as very “invasive” to the page, such as:
- Next up – a floating ad fixed at the bottom of the page
- Read more – shortens and hides part of the article
- Explore more – takes over browser history to affect “back” functionality
- Stories – small, ad circles at the top of the page
What if:
- We are in an (unfriendly) iframe and can’t access the page or page APIs.
- AMP – scripting is very limited, and we can’t use custom UI outside AMP components.
- PWA/SPA – apps built in a structural, restrictive way that may not integrate well with how we do things.
Were these brands more mainstream, it would have been severely damaging for us. In these cases, many of the previously mentioned features would break. In fact, even our base functionality can suffer greatly.
How do we work against this?
In the case of AMP, we have our dedicated AMP component in Google, which loads our widget inside an iframe while retaining most of our abilities.
As far as iframes are concerned, we use messaging and events between the hosts and us, enabling us to do several UI actions even without control outside our iframe cage.
For modern frameworks, we have already started planning for special wrappers written in respective frameworks (such as React) that will enable us to be more in line with the surrounding implementation.
When byte gluttony goes bad
The web is a fast, dynamic place, and whoever gets too slow goes broke. Research shows that even mere milliseconds more in page load can drastically reduce the number of users a site receives.
For such reasons, site maintainers do their best to reduce their loading and rendering times and ensure that UX stays as fluid as possible. It is also one of the cornerstones for initiatives like AMP.
But what happens when said site owners use 3rd party providers, and those 3rd party providers are bogging down the site with many kilobytes (or even megabytes) of their own content? This content can be slow loading, harm UX, and even reduce SEO for the site.
There are several ways in which we make our product more friendly for the host site:
- Lazy loading: our core scripts come in large chunks, which weigh on the host site. However, any module that is not required immediately for the operation of service will be lazy loaded instead to balance the load on bandwidth and page load. In the future, we plan to make it such that any piece of code that is not required for a publisher will not be loaded.
- Monitoring: as part of our performance improvements, we are tracking core web vitals, CLS (Cumulative Layout Shift), FID (First Input Delay), and LCP (Largest Contentful Paint). We also work on features that improve performance on these metrics. An entire stream of developers is dedicated to solving problems in these domains and providing solutions to publisher complaints.
IE for life
Javascript has gone a long way since it first appeared. After the big jumps of ES2015,16,17, we have so many great language features, so much syntactic sugar and shortcuts to make our life easier and the code more readable. CSS has gone a long way too, and every new invention helps us build a more robust experience.
Many new apps and sites may choose to neglect old browsers and direct their attention to the vast majority of users on modern browsers – they live in the Chrome world, and for them, life feels like an idyllic dream.
However, we at Taboola still work with many publishers worldwide who serve users with a wide variety of systems and user agents. We cannot neglect all legacy browsers and devices and must act accordingly while developing and maintaining our code.
It’s always your fault!
After all is said and done, and you have made sure your work is covered, tools and good processes are in place, and everything is working just as you intended. You sit back, relax, and see if your customers are happy with your product.
Then, your customers call to complain that things are not working. You’re baffled, and start double-checking everything you did, considering the most absurd possibilities and any mistake on your side.
Just a few hours later, you find out it was an integration done wrong. Mainly because your client got the wrong notion of what exactly they can do with the service you provided them.
Does it sound frustrating? Yes. Does it seem outrageous that they still blame you, and you are the one who needs to help them out? Yes. But that’s how this works, and if the customer is not pleased, the customer will not keep using your service.
So indeed, it is always your fault, and even though no product is fool-proof, you need to make sure you do everything in your power to avoid them making mistakes.
At Taboola, employees are always on call in case of an emergency. Our experience finding and solving production issues is very high, sometimes mere minutes after a customer complains (or even before). Our product is not bulletproof, but we find and fix it very quickly if there is a problem.
After party
There are many challenges in 3rd party scripting, but the possibilities and benefits are vast. Being able to easily integrate into many products, make and gain value wherever your code lies, and spread that code around the web like wildfire is a huge opportunity. It is no wonder that in order to achieve this, one must be careful and considerate.
Of course, being an expert in web development doesn’t hurt!
There are more points to consider, but I hope the above gave you enough material to understand the basics of this wild, wild web.