Terrible Tiktok Embed Web Performance and my Imperfect Web Component Solution

I had not set out to make a lite-tiktok web component, but I had a spare hour. It only got worse from there.

I recently released version 1.4 of lite-youtube, the little performant web component that just keeps on going. The reason for the version bump was that I added some experimental interaction support for YouTube Shorts, which I think is kinda of nifty and that quite a few people seemed interested in.

This however inevitably lead to yet more questions from people. “Justin, why not a lite-tiktok web component?” Fair question and I had a spare hour the other day so I set out to build a one. The end result was version 0.1.0 of lite-tiktok which produces a more web performance friendly version.

Well, sort of.

You see it turns out the Tiktok embed is terrible on so many levels that my web component is little more than a “stop and hope for the best”. How terrible is the Tiktok embed for your web performance? Let me recount the ways:

  1. The embed loads around 500kB of JavaScript, which jostles around the embed and causes a couple layout shifts.
500kB of JavaScript, I'm sure that's all needed immediately said no one.
Justin Ribeiro
  1. Once that JavaScript is parsed and fires up, it’s going to load at least a dozen placeholder images totaling around 4MB. Why so many? They’re basically thumbnails for other videos that you might see post play of the video in question. Yeah, you may never even see them.
Sure, I'm sure we need all these images before we've done literally anything.
Justin Ribeiro
  1. Then it loads the video. No, not a stream, it downloads the video before interaction or clicking play.
Why they do this is beyond me: the video downloaded, not streamed on interaction.
Justin Ribeiro

For my little 13 second duck video which I used to grab those numbers, that accounts for nearly 10MB for a control I have not interacted with. That’s right, that’s just the embed tossed into a page. No user click, no user hover, nothing. 10MB burned on your wire on top of the parse time and all the usual jank that comes along with such behavior.

On top of this terrible performance is the sad fact that unlike YouTube, Tiktok has no API for their embed. There is no means to control the player through a postMessage or other means, which means for the regular old placeholder-interaction-and-play trick I use for lite-youtube, you simply cannot do this. This means you end up with a double-tap to play for the default web component or you have to rely on the Intersection Observer autoload behavior to smooth out the experience.

What about thumbnail for the video? The placeholder image has to be fetched via their oembed endpoint and cannot be determined by the video’s id much like YouTube. This results in a fetch call to their oembed endpoint to grab the proper link to the image for placeholder use. Note however that fetch is still a factor of 100 (not a typo) faster than waiting for their terrible JavaScript to load fill in the same placeholder on mobile devices.

Which is to say, my lite-tiktok web component is at best a slight improvement but cannot do much to deal with all that cruft.

“Justin, I bet YouTube’s embed loads all kinds of weight too”. On first load, you bet; YouTube’s embed over 700kB of JavaScript, but ditches most of the image and initial video weight (because the video streams). YouTube however has a secret power when it comes to its embed which is the main site service worker; if you’ve visited Youtube or second load the embed, the service worker limits YouTube’s load to just 32kB of JavaScript.

Oddly enough, TikTok uses a service worker as well on their main site but the embed doesn’t utilize it in my testing. While the embed does use disk cache with somewhat reasonable headers, the problem ultimately becomes one of the weight of the media sources that it crushes the wire. Even the same video embedded twice won’t hit the disk cache for all media assets, resulting in quite the wire hit: my 13 second duck video, loaded twice on the same page via intersection observer at different times pulls 16MB on the wire.

Frankly, I’m just not a fan of the Tiktok’s embed even with my intersection web component. The media weight is simply too high given what may not be a user interaction. If they had any resemblance of an API to control playback, this could easily be worked around. In the mean time lite-tiktok is around albeit not ideal by any means. If you want, I talk about it more in this video;

And hey, TikTok’s source code says is hiring, so maybe they’ll get some web performance expertise and make the web a little nicer for their embeds.

Scouring their embed source code, I ran into this line. Hire some web perf people, please.
Justin Ribeiro