A *bit* about content ratings
A dive into how Vimeo stores and keeps track of a video’s content ratings and respects the visitor’s viewing preference.
Video is power, and with great power comes great responsibility…responsibility that no one stumbles across something they didn’t sign up to see. Vimeo enables creators to rate their videos and viewers to filter by ratings to keep our incredibly wide audience safe. Content is consumed by millions of viewers, of different ages, from different countries, all with different viewing preferences. We have to ensure that we continue abiding by the ever-changing viewership laws around the world considering how global a platform Vimeo is.
Viewing unwanted content can be an unpleasant surprise. We’re doing our part to keep audiences safe.
A recent change in UK law spurred us to revisit our content rating logic and process. The new law stipulates that when certain users attempt to view a mature or unrated video that is publicly available, we must require the user to log in as age validation (see Figure 1). This was put in place to keep kids on the internet safe from mature content.
With this change, we made several product updates to tie the whole rating process together from an uploader and video manager’s perspective.
- The uploader is now prompted to rate their video and indicate whether it includes an advertisement immediately after upload (see Figure 2).
- The uploader or video manager can now manage their content ratings in the same place where they manage their privacy settings.
- The uploader or video manager now sees mature or unrated badges or an indicator when their video’s content rating is locked by a Vimeo moderator.
Although I was primarily responsible for the UI changes, I went down the rabbit hole of content ratings in our backend system to discover our absolutely brilliant way of storing and filtering by content ratings.
The back end
The concept of content ratings was introduced into Vimeo quite a while ago — in fact, the earliest commit I could find dates back to almost a decade ago. With a stroke of luck (and, let’s be real, Vimeo loyalty), the developer who set up content ratings in our backend system 10 years ago, Sean, was on my team! We hopped on a Zoom to break down the legacy code’s complex bitwise operations that I’d been trying to decipher.
Before we delve into the thick of it, I want to mention that we made the technical decision to add advertisements as part of the content ratings data structure. This ultimately means treating the
advertisements flag the same way we treat a
unrated flag — all under the same matrix. This decision avoided adding an entire column to our already very large video table.
When I first looked at the code, I was expecting some sort of mapping for every rating on a video, maybe something like in Figure 3…
…or even an array that contained just the values of the selected ratings, like in Figure 4.
I had never considered a data structure that could potentially condense all of these booleans into a one single compact value.
In reality, Vimeo’s back end stores a video’s content rating as one value: the sum of all its ratings. This is called a bit field. Instead of storing a bunch of booleans for every rating on a user or video, or having an array of selected values like I had assumed, we actually have one compact bit field to represent all the trues and falses for each rating. This is an extraordinary space saver, as we are avoiding having a hashmap or array (although, I do admit, these are much more readable). Our method can also easily accommodate for additional ratings to be added to this structure —
advertisements, in our case. It calculates at an incredible speed whether a video passes the user’s content rating acceptance criteria, and reduces memory consumption by “packing” all the information. Although treated like a content rating in the back end,
advertisements cannot be filtered in the viewing preferences. This is why, by default, all viewing preferences include
advertisements— a value of 256 (see Figure 5).
To understand further how a video’s content rating is accepted by a viewer’s content rating preferences, we’ll look at a simple scenario of Radhika and David, each with unique viewing preferences, encountering the same video. We will ultimately be able to determine how the back end accepts or rejects a video based on the user’s viewing preference.
The binary and bitwise
The first premise is that a fresh new video not yet assigned a content rating has a default rating of 3. By default, a video is not rated and the rating is not locked by a moderator, so we get the sum of these two applicable properties, as shown in Figure 6.
Let’s say that this particular video that is being uploaded and rated contains drugs
[RATING_EXPLICIT_DRUGS] and nudity
[RATING_EXPLICIT_NUDITY]. To calculate this video’s rating, as shown below in Figure 7, we would add up all the new ratings and subtract what no longer applies — in our case, it is no longer unrated once we give it a rating.
Next, let’s convert our value to binary (see Figure 8).
Our video’s content rating comes out to 82, or 1010010 in binary form, once we rate this video with
nudity. Now, let’s see what happens when two viewers with different viewing preferences come across this video. This is where the bitwise fun happens!
A user’s content rating filter preference is calculated in the exact same way: as a single value that is the summation of all the ratings that the user is okay with seeing.
Let’s do a quick scenario with our two different users, whose names, you’ll recall, are Radhika and David.
Figure 9 shows that Radhika is okay with watching videos that have the ratings of
violence (32) ,
not locked (2),
unrated (1), and
advertisements (256), yielding a value of 319, which converts to a binary of 100111111.
You see in Figure 10 that David is okay with watching videos that have the ratings of
violence (32) ,
not locked (2),
unrated (1), and
advertisements (256), yielding a value of 383, which converts to a binary of 101111111.
Radhika and David each come across a video containing drugs and nudity.
Now that we have David and Radhika’s viewing preference values, we can use the & bitwise operator to determine whether the video’s content rating meets their viewing preference criteria. If
CLIP RATING & USER PREFERENCE results in the video rating (see Figure 11), the user should be able to view the video.
Let’s do the math! See Figure 12.
The numbers don’t lie! Looks like Radhika’s viewing preferences don’t let her view the video, while David’s do!
Let’s take a second to soak in the beauty of this data structure. We are able to represent the user’s entire content rating preference in one single value instead of having to keep track of nine different rating variables. We not only save space by grouping multiple booleans into one integer value, but we are rapidly and efficiently able to determine whether a video meets the user’s viewing preferences using bitwise operations. This enables us to skip iterating through the videos’ ratings and the user’s preferences and comparing each value to another. Think of all the iterations and comparisons we get to avoid by using bit fields and bitwise operations instead of iterating over a hashmap. What’s notable is how large of a scale these operations are occurring on — imagine the millions of users who are searching and browsing through videos on Vimeo, constantly loading large quantities of videos. Every video loaded requires a content rating calculation to determine whether it should be displayed to each user. Bit fields let us do this at an incredible speed.
Thus, I was pleasantly surprised to learn that bitwise operators and bit fields, a concept my college professors barely grazed over during perhaps a single lecture, had an extremely applicable use case on something I was working on. Bit fields offer an optimal solution to a data structure that would otherwise consist of sometimes dozens of boolean values. The subject of content ratings is a beast of its own, but at least it’s a performant beast that keeps users safe!