Embeddable Javascript snippets are extremely common nowadays. You can add short javascript snippets to your website to measure analytics (Google Analytics, Mixpanel, Segment…etc), to A/B test your site (Optimizely), to measure the impacts of your advertisements (Facebook Advertisement & Retargeting snippets) and in the case we explore, for Sonar, to create a new channel of communication with your users…via text!

Why would I make an embeddable Javascript snippet?

If you have a product that relies on proper integration into your clients’ website, a javascript snippet is probably for you! With an embeddable Javascript snippet, you’ll make it easier for your clients to understand & use your product. Here are just some of the benefits:

  • Less work for client: When you sell, you can say: “Just paste this one line of code in your codebase and you’ll see what we’re all about!” So now, when they say, “we’ll do it when we get time,” you can tell them that putting off something like that is downright lazy! All you asked was for them to PASTE something! :P [Don’t tell your customers that, but do make their lives as easy as possible.]
  • Client sees value quickly: Works great for Google Analytics! One line of code and clients start getting page view information left and right. Seeing that small amount of page view information makes clients excited about all the possibilities of Google Analytics [sub your products’ name here]!
  • Easy Demo-ing: Are your clients wondering how your widget will look on their site? Just tell them to paste the snippet in their staging environment and see it in action! This makes demo-ing your product much easier!
  • Your code is less reliant on client: Clients are smart people (after all, they’re using your product), but ideally your code doesn’t rely on their implementation of it. Embedded scripts that import a safe JS file from your server into client’s site allows you to change your code over time and improve it.

I’m sold! How do I make one?

There are four components to making an embeddable Javascript Widget:

Embedder / Loader Script:

This is the short snippet of code that you want your client to paste into their website. It is responsible for going to your server and getting any other javascript code (Payload script) that might be necessary to make your widget run!

You have to keep the following things in mind while creating an embedder script. All of these are very important:

  • Asynchronous: You don’t want to slow down your client’s website in any way (otherwise they’ll hate your product!). There are several things we can do to make sure that our embedder script runs asynchronously and does not block any of our clients other code.
  • Keep it short!: Don’t give your clients 100 lines of code to add to their website, that will be annoying to them! Aim for 15 lines or less.
  • No global variables: You don’t want to create any variables that might mess up your client’s code. Don’t set the global variable x to 10, what if they are using x in their javascript functions!? Therefore, we’ll work within our own namespace.
  • Self-reliant: Different clients have different web environments, so it’s best not to assume, for example, that you can use jQuery functions. Further, don’t go out and get javascript libraries to use, as you never know if your javascript library will conflict with another version they might have. Simply speaking: stick to plain javascript.
  • Cross-browser: You’ll need to make sure that your widget works on the browsers of your clients’ clients! So make your code compatible across IE, Firefox, Chrome, & more (depending on who your clients’ clients are!)

Below is our annotated embedder snippet. The comments explain how it accomplishes the goals above. I also recommend you visit this site http://friendlybit.com/js/lazy-loading-asyncronous-javascript/ for an even fuller explanation of this code.

<script data-version='v1' data-widget-id='your-clients-id' id='unique-embedder-id' type='text/javascript'>
  // "data-version": It's useful to put the version of your embedder script in the "version" data attribute.
  // This will enable you to more easily debug if any issues arise.
  // "data-widget-id": This ID allows us to pull up the correct widget settings from our database.
  // It's a "client id" of sorts.
  // "id": This HTML id allows us to refer to this embedder script's location. This is helpful if you want to inject html
  // code in specific places in hour hosts's website. We use it to insert our payload script into the <head> tag.

  //We wrap our code in an anonymous function to prevent any ofour variables from leaking out into the host's site.
  (function() {
    function async_load(){
      //BELOW: we begin to construct the payload script that we will shortly inject into our client's DOM.
      var s = document.createElement('script');
      s.type = 'text/javascript';
      s.async = true;
      // Below is the URL you want them to get your payload script from!
      var theUrl = 'http://www.your-website.com/assets/your-payload-script.js';
      // At the end we tack on the referrer's URL so we know which website is asking for our payload script.
      s.src = theUrl + ( theUrl.indexOf("?") >= 0 ? "&" : "?") + 'ref=' + encodeURIComponent(window.location.href);
      // This finds the location of our embedder script by finding the element by it's Id.
      // See why it was useful to give it a unique id?
      var embedder = document.getElementById('unique-embedder-id');
      // This inserts our payload script into the DOM of the client's website, just before our embedder script.
      embedder.parentNode.insertBefore(s, embedder);
    }

    // We want the our embedder to do its thing (run async_load and inject our payload script)
    // only after our client's website is fully loaded (see above).
    // Hence, we wait for onload event trigger. This no longer blocks the client's website from loading!
    // We attachEvent (or addEventListener to be cross-browser friendly) because we don't want to replace our
    // client's current onLoad function with ours (they might be doing a bunch of things on onLoad as well!)
    if (window.attachEvent)
      window.attachEvent('onload', async_load);
    else
      window.addEventListener('load', async_load, false);
    })();
</script>

https://gist.github.com/nbhartiya/7aadca9e98ddbc0850d2

StyleSheets (Optional):

If you’re making anything appear on your client’s site or changing the appearance of their site, you might want to embed stylesheets into their website. Typically, the Payload script embeds stylesheets into the host site…something like “hey server, give me that stylesheet I made for this widget, okay got it, now let me embed it into the head tag of this host site, making these styles available to my widget.” We’ll point out how this is done in the Payload Script section. This process is, of course, slower than using inline styles only. So if you have little styling that’s necessary, you can avoid creating a separate stylesheet and save time.

Payload Script:

This longer bit of javascript code lives on your server (or you could put it up somewhere in AWS). The Embedder / Loader script pulls it into your client’s website asynchronously. The payload script is likely the meat of your javascript code–the thing that your customers are paying you for (hence, I call it ‘payload’). This bit of code is most customized to you (it’s whatever service you provide to your clients!), so I won’t go into a lot of detail. However, I will give suggestions on how to add stylesheets into your host site and how to make sure your payload script doesn’t conflict with your client’s website, below.

https://gist.github.com/nbhartiya/51432bfbfc8a7563df97

Controllers / Routes on your Server:

These controllers and routes will handle requests. For example, you need to make your Payload script accessible to someone just by visiting a URL on your website. You might also want to grab something from your application’s database (i.e. settings for how the widget should look for a particular client) or save some analytics data to your database that the payload script periodically sends. But, how do you make a payload script accessible to the embedder script? How do you tell your server to listen to requests from a different origin (your client’s website)?

In rails, you can make your payload script available publicly by whitelisting your asset with the ‘non-stupid-digest-assets’ gem https://github.com/alexspeller/non-stupid-digest-assets. That way your javascript file and stylesheets are accessible without a weird string of characters after it!

To make your controllers be able to process data (i.e. save analytics information on your widget or to get your customers’ specific settings for their widget) you’ll need to enable CORS or Cross Origin Resource Sharing. Learn more information on enabling this here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

For POST requests tracking data for our widget, we added the below lines of code into our ruby controller.

In widgetclickevent_controller.rb

class WidgetClickEventcontroller < ApplicationController
    protect_from_forgery except: [:action]

    def action
      headers['Access-Control-Allow-Origin'] = '*'
      # Your code
    end
end

For GET requests getting the settings of our widget, we used the below code in our ruby controller:

https://gist.github.com/nbhartiya/067d6cad778ed7fded17