Making external embeds play well with our content

How we handle fb/twitter/youtube/<insert-a-website-here> embedding in our content to make them play well with the styling of our website.

Being a news website, we frequently cite and embed external content mostly Youtube, Twitter and sometimes Facebook. All of these websites provide their embed codes which is fairly easy to use in the sense that you can quickly copy the embed code and paste it in your CMS’s (traditionally Wordpress) HTML editor.

Here is an example of some common embed codes for various websites —

Problem with pasting embed codes directly is -

  • They eat a lot of user bandwidth with their script and content downloads.
  • The download size increases a lot more if there are multiple embeds in a single post.
  • Embeds like Youtube and Facebook videos even start downloading their initial video files too, even if users have not yet actually played the video.

To overcome these issues we have implemented our content’s HTML rendering such that we don’t render these embed codes at all. Instead, we render generic HTML tags like figure or div with all the required options as data- attributes of the tag.

For example, if we want to render the following youtube video, instead of rendering normal iframe that will start loading huge data, we generate the following html,

All the data attributes here have been fetched from the Youtube’s oembed API.

Our CMS helps in this process a lot, mostly because it was built with having full control over our content in mind. This CMS, which we internally like to call scribe, is block based and uses Kattappa as the rich text editor. Each block maybe a piece of text, image or embed url (or a custom block that can be built as a plugin).

So in the editor, we do not ask editors to paste the embed codes that they have copied from websites. Instead, we ask them to just paste the url which they would like to embed. In case of youtube, it is just this- https://www.youtube.com/watch?v=QigIssNSOww. Same is the case for other websites like fb, Twitter, Instagram, etc. Then during the content publishing -

  • We fetch metadata about these embed URLs from their oembed APIs. Most of the services have their oembed APIs except Facebook. For Facebook, there is graph API.
  • Extract the data that we want that will help in rendering the embed in browsers and save to DB so that we don’t have to fetch data every time.
  • Then generate html using empty figure tags with all the metadata as data- attributes.
  • For some of the embeds, like youtube, vimeo, the generated html also contains the poster of the video and a play button to give it the appearance of a video.

So instead of rendering an iframe for youtube, we just render a figure with a background image and a play button.

The main user interaction part is taken care of by our frontend code where we scan through these tags by querying [data-embed-loaded=false]. Then depending on the type of embed, eg. Facebook, Youtube, etc, we make them clickable, and render actual content on click. For this, we have created an internal library that we call lazy-x.js (where x stands for embed). Here is a snippet of javascript that takes care of youtube DIVs -

Same approach is taken for other types of embeds as well. All of them require careful studies of their embed library APIs and availability of embed data through oembed and graph APIs.

Here is another snippet of how we render fb posts/videos -

This one has not been optimised yet as the above snippet directly renders the fb posts or videos instead of loading it on a click but we have found the solution and it will be updated soon to behave like youtube videos.

Final code is where we iterate through embed nodes and call their functions-

The render logic of youtube, vimeo and vine; twitter and instagram are equivalent.

These things helps external embeds play well with our content and also helps in giving these embeds the theme of our website instead of their own styles (except Twitter and Instagram and fb posts).

Our next effort will be to make render/play/pause these embeds when they come in and go out of the viewport as right now, we just query for data-embed-loaded=false and call their equivalent function from lazy-x.

Here are some references to look into if you want to customise the embeds the way we did -

  1. Instagram — https://www.instagram.com/developer/embedding/
  2. Twitter — https://dev.twitter.com/web/javascript/initialization
  3. Youtube — https://developers.google.com/youtube/iframe_api_reference
  4. Facebook — https://developers.facebook.com/docs/plugins/embedded-posts/