Picture of Michael Lee

iOS Scriptable YouTube widget

Written on January 20, 2021

In this article, I’ll be showing you how to add a YouTube widget to your iPhone that pulls in a couple of stats from your YouTube channel—total subscribers and total views.

What will it look like on my phone?!

Great question, here’s a screenshot of the widget on my phone with my excellent channel stats 🥳

Screenshot of iPhone Home Screen with YouTube widget

Looks nice right? You want one on your phone too, you say? Well let me show you how!

What it won’t do

Wait…before we get started let me tell you what the widget won’t do for you. It won’t create new videos for you. It won’t give you more subscribers. It won’t make you a YouTube sensation.

Unfortunately, you’ll have to still put in the work to make all your YouTube dreams come true.

What the widget could do is give you a little motivation every time you look at your iPhone’s Home Screen to keep creating and putting your work out into the world.

I hope you still want this widget on your phone…I just wanted to set the right expectations first 😬

What you’ll need to get started

In order to get this widget on your phone and working correctly you’ll need four things.

  1. You’ll need an iPhone with iOS 14—the first version of iOS where widgets appeared.
  2. An app called Scriptable.
  3. A Google API key—you can follow instructions here to set up an account and get one.
  4. A little patience as there’s some code involved. No worries if you’re not a coder, I’ll do my best to guide you along and make it as not scary as possible.

Once you’ve got all four of the items in the list above, it’s time to grab your YouTube channel ID.

Where to find your YouTube channel ID

The easiest way to grab your YouTube channel’s ID is to pull up the channel in your browser.

In the address bar, you should see,


Where *** represents your channel’s ID.

Screenshot of YouTube channel highlight the channel ID

Write your channel ID down or copy and paste it somewhere because you’re going to need it in a little bit.

But wait Michael, I’m MKBHD and I’ve got a totally sweet short URL for my channel like this,

Screenshot of MKBHD's YouTube channel

How do I get my channel’s ID?

Glad you asked Marques!

This is how you find your channel’s ID if you’ve got one of those fancy short URLs for your YouTube channel.

  1. Click on any video in your channel
  2. Hover over your profile’s name on the video page, you’ll notice that it’s actually linking to your channel with the non-fancy, long obscure ID.

    Hover over YouTuber name to reveal channel ID

  3. Right click over your name and select the copy link and now you’ve got your channel URL with the ID. Throw away everything but the channel ID.

    Right click on name to copy the channel URL

The code

Now comes the part where it might get a little scary if you’ve never touched code before, but I promise I’ll try to make it as not scary as possible.

In this part we’ll put some code into Scriptable and then use some of the things we’ve been collecting to finally get our widget set up.

  1. Open up Scriptable and create a new script by pressing the + button in the top right hand corner.

    Tap on the top right plus symbol to create a new script

  2. Copy and paste this code in there,

     const apiKey = ""
     const channelID = ""
     const channelName = "My channel"
     if (config.runsInWidget) {
       const widget = await createWidget()
     async function getData (channelID, apiKey) {
       const url = `https://www.googleapis.com/youtube/v3/channels?part=statistics&id=${channelID}&key=${apiKey}`
       const r = new Request(url)
       const body = await r.loadJSON()
       return body
     async function createWidget() {
       const widget = new ListWidget()
       let ytData = await getData(channelID, apiKey)
       ytData = ytData.items[0]
       const subscribers = widget.addText(abbreviateNumber(ytData.statistics.subscriberCount, 2))
       subscribers.font = Font.boldSystemFont(36)
       const subscribersLabel = widget.addText("Subscribers")
       subscribersLabel.font = Font.semiboldSystemFont(10)
       const viewsBlock = widget.addStack()
       const viewsContainer = viewsBlock.addStack()
       const viewSymbol = SFSymbol.named("play.fill")
       const viewImage = viewsContainer.addImage(viewSymbol.image)
       viewImage.tintColor = Color.white()
       viewImage.imageSize = new Size(12, 12)
       const views = viewsContainer.addText(abbreviateNumber(ytData.statistics.viewCount))
       views.font = Font.semiboldSystemFont(20)
       const viewsLabel = widget.addText("Views")
       viewsLabel.font = Font.semiboldSystemFont(10);
       let channelLabel = widget.addText(channelName)
       channelLabel.font = Font.semiboldRoundedSystemFont(10);
       let reloadStack = widget.addStack()
       let reloadSymbol = SFSymbol.named("arrow.triangle.2.circlepath")
       let reloadImage = reloadStack.addImage(reloadSymbol.image)
       reloadImage.tintColor = Color.white()
       reloadImage.imageSize = new Size(8, 8)
       reloadImage.imageOpacity = 0.9
       let today = new Date()
       let updateTime = `${today.getMonth() + 1}/${today.getDate()} ${zeroPad(today.getHours())}:${zeroPad(today.getMinutes())}`
       let updateLabel = reloadStack.addText(updateTime)
       updateLabel.font = Font.semiboldRoundedSystemFont(8)
       updateLabel.textOpacity = 0.9
       const startColor = new Color("#ff0000")
       const endColor = new Color("#e40000")
       const gradient = new LinearGradient()
       gradient.colors = [startColor, endColor]
       gradient.locations = [0.0, 1]
       widget.backgroundGradient = gradient
       return widget
     // Credit: https://stackoverflow.com/a/32638472
     // Thanks to https://stackoverflow.com/users/1438550/d-deriso
     function abbreviateNumber(num, fixed) {
       num = Number(num)
       if (num === null) { return null; } // terminate early
       if (num === 0) { return '0'; } // terminate early
       fixed = (!fixed || fixed < 0) ? 0 : fixed; // number of decimal places to show
       var b = (num).toPrecision(2).split("e"), // get power
       k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions
       c = k < 1 ? num.toFixed(0 + fixed) : (num / Math.pow(10, k * 3) ).toFixed(1 + fixed), // divide by power
       d = c < 0 ? c : Math.abs(c), // enforce -0 is 0
       e = d + ['', 'K', 'M', 'B', 'T'][k]; // append power
       return e;
     function zeroPad(numToPad) {
       if (numToPad > 9) {
         return numToPad
       } else {
         return `0${numToPad}` 
  3. Add your API key to the first line in the code that starts like this,

     const apiKey = ""

    You’ll want to add the API key in between the two quotation marks "". Once you do, the first line of code should look something like this,

     const apiKey = "yourAPIKeyFromGoogle"
  4. Add your channel key to the second line in the code that starts like this,

     const channelID = ""

    Again, you’ll want to add the ID in between the two quotation marks "". Once you do, the second line of code should look something like this,

     const channelID = "yourChannelIDWeGrabbedEarlier"
  5. And that’s it for the coding portion! Now let’s add just a little bit of flair by giving our script a name, icon and color. You can do this by pressing the icon in the bottom left corner of your screen.

    Tap on the icon to get to the script settings

    You’ll get this screen where you can set a name, icon and color.

    You can change the name, icon and color of the script from this screen

  6. Now that you’re done. Close the window and tap Done to exit our of your script. We’re ready for the moment we’ve all been waiting for…the widget!

The widget

In this section, I’ll show you how to get the new Scriptable widget on your Home Screen. If you’re already familiar with this process, feel free to skip over this step and go to the next section.

To add the widget to your Home Screen you’ll want to do this.

  1. Tap and hold anywhere on your Home Screen until the apps start to jiggle.

    Gif to show app jiggle on iOS Home Screen

  2. Tap the plus + button in the top left hand corner,

  3. Scroll down until you see Scriptable and tap it.

  4. Select the small widget (which should be the default one shown) and tap Add Widget

  5. Once the widget is added to your Home Screen, you’ll see the widget display, Select script in widget configurator, tap the new widget and you should get the widget configurator.

  6. Next to the label, Script tap Choose to select the new YouTube script you had added into the Scriptable. Once you’ve selected it, tap outside of the configurator to be taken back to your Home Screen.

    Photo of Scriptable configurator

  7. 🥳 do a little dance cause now you’ve got your very own YouTube widget on your Home Screen to go with you wherever you go. The widget is proof that your work is appreciated by viewers from all over!

Get fancy

Now that you’re able to see your channel’s subscriptions and video views count, I hope it motivates you to keep putting out great videos to share with the world!

If you’re feeling adventurous, try enhancing the widget in Scriptable to make it your own. With a little knowledge of JavaScript, some imagination and the incredible, well put together doc, you can improve it to really match your personal brand.

Screen shot of Michael's widget and a custom MKBHD widget

If you’re looking for customizations but can’t be bothered with more code, you can purchase the enhanced code. The code comes with easy-to-follow instructions to add a custom logo and background to your YouTube widget.

Think less and start

Written on January 17, 2021

During Christmas my family was gifted a new kitchen appliance which my wife and I were both really excited about—a toaster oven and air fryer. We’ve had a toaster and an air fryer before, but this thing did both and more.

After unpacking it what we did next was I sat down on our couch and opened up the manual and my wife grabbed a piece of toast and began buttons.

This is an example of what happens every time my wife and I bring home a new appliance.

This speaks loudly to how my wife and I learn about things and build new habits. My wife tends to jump right in and learn by doing, while I will usually sit and try to learn about something first and try to anticipate different scenarios to achieve my goals.

What I’m learning from my wife and recently from my friends is that sometimes doing is more valuable than thinking first.

Just start

For a while I had become obsessed about sleep schedules of successful people.

Bob Iger, former CEO of Disney, in his book, The Ride of a Lifetime, shares that he wakes up at 4 AM to have time for creativity to start the day.

The Rock, also wakes up around 4 AM to start his day with exercising before his family rises.

Casey Neistat, of YouTube fame, starts his days at 5 AM and sleeps on average of 4 hours of sleep a night.

Recently in November, my friend, Nick Ang, took part in National Novel Writing Month (NaNoWriMo for short) to work on a personal goal of his—to work on a novel. During the month he shared tweets about getting up early to spend time writing his novel.

It was inspiring.

As a response to a tweet about creative and productive times during the day, Nick of course shared that for him it was early mornings.

I then asked if he had some advice for making the habit of waking up early stick and to my surprise and delight, he shared this response,

How to get started with flossing

I really love Nick’s response of the story of his trip to his dentist and their advice on starting first and then worrying about technique later.

I can definitely learn from this.

As an engineer, I easily fall into a place where I try to look at something and analyze as many outcomes or prepare myself—by reading manuals—before diving in.

While it’s helpful in scenarios where time spent up front has proven to help mitigate issues that might arise. What’s also important is how you solve for issues that arise along the way.

Your mileage may vary, so start

Going back to our new toaster, while reading the manual definitely told me how to set the appliance in toaster mode. What it failed to teach me was what setting to put it on to get the desired browning of my toast. In other words, what a manual and thinking up front failed to teach me is how to solve for, “your mileage may vary”. Toasting in this appliance varies based on what kind of toast, quantity and preference of toast level—things the manual can’t teach me.

In the same way that reading a book on how to play baseball won’t make you a baseball player adept to playing in a major league game. Perhaps the quicker way to achieving your goal may be instead is to get started and build first the muscle for the habit you’re trying to create. And then once the muscle is built, seeking for help to improve your technique to go further in your habit.

A book can only take you so far and while your mind can go further, often the reality of how things play out will be fairly different because our mileage will vary. But what doing allows us to do is learn and adapt as we move closer along the path of realizing our goals instead of on a couch—stationary—in the hypotheticals of our mind.

Forget the tools, focus on the experience

Written on January 10, 2021

For weeks the front entrance to my house had become an eye sore. Residue left from winter, my son’s new obsession with excavating our yard in hopes of finding dinosaur fossils and shifting of debris as people walk back and forth on the path.

This evening I decided I had had enough of the eye sore and grabbed my broom and started cleaning. As I started I saw my son disappear at the side of the house only to reappear a few moments later with another broom excited to help out.

But before starting he held out the broom he retrieved in a gesture to trade his for mine.

The broom he offered was one we had bought from a bargain store for very cheap. The handle was made out of cheap metal and the bristles were separating and falling out. My broom was purchased at a higher price from a hardware store. The handle was made out of wood and the head had very tight and short bristles.

As you can imagine the quality difference was quite stark and my son knew which tool was better.

Not bothered by which broom I would use, I made the swap and watched as my son proceeded to clear out the messy areas.

With the broom he ended up using–the better broom–I noticed he was struggling to use it. The weight of the broom is a little heavier and because the bristles are tighter, much more energy must be exerted in order to get the head to move in the direction you’d like.

As you can imagine, he was hard at work and the level of effort he exerted to properly use the broom was much higher. Don’t get me wrong, I was super proud of him and enjoyed the assistance he provided. But I knew the broom I had–the cheaper broom–would’ve made his job easier.

I then proceeded with cleaning with the cheaper broom. While not as efficient but since I was experienced in using the broom, I could still clean the pathway. The trick with the broom was to make smaller, quicker strokes to move debris more efficiently.

Cleaning with my son got me thinking. Of how this experience was very much a metaphor for how I’ve approached solving problems as a developer early in my career. I often obsessed over which tool was best suited to solve my problems. When in reality any number of tools would be right for the challenge.

I would get fixated on what I thought was the better tool, instead of focusing on simply the process of solving the problems in front of me with the tools that I already had.

Like my son, I grabbed the “better tools” but ended up exerting more effort in order to achieve the things I wanted to.

It’s only now that I realize that it is less about the tool that is in your hand that yields the better results but it is enjoying the process and growing with your tools in experience.

Give a master artist a crayon and what they are able to produce will be far better than what I or any average person can produce with an Apple iPad Pro, Pencil 2 and Procreate.

I’m far from being a master sweeper, but by having experience and the physical advantage compared to my son, I’m able to achieve the same or better results with the cheaper broom than what my son was able to produce with the better broom.

However as I sit here writing this essay, I realize he was likely to be more focused on spending time with his dad versus the tool he had for the task. Sweeping with him was a reminder to focus less about the tools and focus more on the experience.

Streak rules

Written on January 3, 2021

In a productivity app I’m currently working on I wanted to incorporate the idea of a streak feature.

Streaks are nothing new in the world of productivity. Famously popularized by Jerry Seinfeld’s productivity secret.

In Mr. Seinfeld’s case, he used a calendar to mark each day he sat down to write. Eventually the marks create a chain and keeping the chain going (or not breaking the chain) was pressure enough for him to sit down and write every day.

I’ve iterated a few times on my solution for streaks in my app. And before I share where I landed I wanted to work a little backwards.

What I mean by this is there are multiple ways to implementing a streak. The most common one as seen in apps like Snapchat, is to award users with an unbroken streak as long as they interact with the application in some way every 24 hours.

And so before sharing my solution, I’d like to challenge you. If you’re reading this and also implementing a streak, first think about what you would like the people using your application to do on a regular basis in order to keep the streak going.

Once you’ve determined that, I also challenge you to think about both the positive and negative effects of the streak. While a streak is motivating is it your intention to have them show up to your application for the sake of keeping the streak going?

My first iteration of the streak in the system was pretty straightforward, determine whether the person had completed a task within the past 24 hours. If they did, then keep their streak going.

But then as I was participating in the streak function—while motivating—I noticed something that didn’t fit my life style. My weekends are less regimented. I enjoy spending time with my wife and kids and often times that means time away from my computer.

While this fits my use case, I think it will also have benefits for others as well that aren’t like me. While I’m definitely for productivity, I’m also strongly for a healthy mental well-being. For this reason my next iteration will likely have the ability to set up a schedule to not count against the streak. Like a pause button. To allow for more mindful productivity.

Implementing a pause is still aspirational at the time of writing this article, but I thought I’d share my solution.

The models

In my application there are two models which work together to achieve the streak.

The user model which is used to represent a person using the application and then a task model used to represent tasks.

The user model contains three specific fields that are used for the streak function. Those fields are streak, last_streak, streak_updated_at.

The streak field is a numerical field that is used to keep track of the active streak.

The last_streak is used to keep track of the last streak. If there is only a single streak, then the streak and last_streak are the same. The reason I have two fields is that if for some reason a user had lost their streak, I want a way to recover their hard earned streak for them.

The streak_updated_at field is a timestamp field which gets updated when the streak gets updated. This is then used to determine whether the person has completed a task within the past 24 hours.

The task model contains two fields which are used for the streak function. Those fields are completed_at and streaked.

The completed_at is a timestamp which updates the moment a person marks a task as completed.

While the streaked field is a boolean which also gets updated the moment a person marks a task as completed but only the first time. By default this field is set to false. But when completed, it gets marked as true. I did this because sometimes you mark a task as completed but it might not be true. I also didn’t want a person to game the app, so streaked acts as a way to determine if a task has already been accounted for towards a streak.

The logic

When a person marks a task as complete for the first time, the application will determine if the last task was completed within 24 hours by checking the streak_updated_at task of the user model. If it is within the 24 hours, then the streak and last_streak increases.

The task also then gets marked as streaked by having this field marked as true. With the completed_at set to the current timestamp.

When a person marks a task that has been marked streaked to true then the application will just update the task’s completed_at with the current timestamp but the streak won’t be updated.

How is 24 hours determined?

The last piece to the streak is that every person using the application has a common time to complete a task. That time is coordinated universal time (UTC) a time is commonly known amongst computer servers.

When a task is completed, the application checks to make sure that it is completed in the current UTC day. Then it checks to make sure the streak_updated_at time was completed within the last UTC day. If both criteria are met, then the streak is incremented.


The purpose of this article wasn’t to provide a streak solution in a particular programming language but it was more as a strategy based around rules for what the streak should enforce.

I hope with what I’ve shared it’ll give you ideas on how you can implement your own streak feature in an application you might be involved in.

2020 annual review

Written on December 27, 2020

2020 sheesh…am I right?

To say that this year didn’t rock everyone’s lives would be an understatement.

It definitely impacted my life in many ways–some positive and some not so positive.

This is the first time I’m doing an annual review. The reason why I wanted to do it is mainly 2020 felt in many ways aimless. I think the natural flow of life for 2020 was to hurry and get to the end of the year so that we can start anew in 2021.

But before I do, I wanted to pause and remember the positive things in 2020 and be mindful of where 2021 is heading.

This essay is composed in two parts:

  • A section on what went well
  • A section on what didn’t go well

This format was inspired by Chris Guillbeau’s annual review.

What went well?

  • Took an old project and made it into a project for my kids

    A couple of years back I illustrated a bunch of food items and shared them on Instagram. When the lockdown from the pandemic came around, I decided to turn my illustrations into coloring pages for my kids to enjoy and learn Korean. Surprisingly I found coloring them to be relaxing as well.

    I eventually created enough pages and put them together to make an e-coloring book.

  • Met pretty regularly with a group of guys who work on side projects

    Pre-COVID, I had been meeting pretty consistently with a couple of guys – John and Shaun – to talk about and work on side projects together. While the focus was side projects, the group turned more into a time to support each other in life.

    We had gone through seasons of work, life and side projects together and it has been nice to have that support in many ways.

    This year the group was expanded to also include Nathan and Dan.

    It’s been neat to learn about the different projects we’re all interested in and helping with our mixed talents in achieving our side project goals.

  • Joined a tiny, writing club

    A Twitter friend of mine reached out one day out of the blue and asked if I wanted to join him and another Twitter friend of his on this thing called a word raft. I initially told him no, because life felt chaotic with three kids and the pandemic.

    But I eventually joined and it has turned out to be quite the delight.

    Shime, Nick and I have been rafting together for six months where we’ve published consistently every single week.

    I’ve always wanted to write more consistently and I’d say joining word raft was the single best decision in contributing to my consistency.

    Recently we have welcomed a couple of new writers into the word raft–Haikal and Pieter–I’m quite excited to continue to deepen our writing and collaborate with such brilliant writers.

  • Started using tools that’s helped me get more productive

    Prior to this year, I had been a cheap-skate when it came to tooling. But I decided to change that. With a more demanding job this year, I finally said I wanted to invest in good tools that would help me save time and energy in the things I wanted to achieve.

    As I result, I have bought more software than I have in a long time and I have been happy with what each tool brings to my productivity.

    The tools that’s made the most impact–Things, Nova, Toolbox Pro, Transmit, Tempo and Reeder.

    If you’re ever hesitant about buying software, I’d say just go for it. Especially if the software has been around for a while. There’s a reason for their longevity. They provide a ton of value for customers in which they serve.

    I have been someone who has been hesitant about buying expensive software – especially as a programmer. But I’m learning that supporting other developers feels great and the tools that they make improves my life in ways than not having access to their tools.

  • Bought a Herman Miller Embody chair which has improved my posture and back pain

    For a very long time I have had issue with my posture and back. There was a period in my life a few years ago where standing and brushing my teeth would cause my back to get thrown out of place.

    For this reason and from a little nudging from my wife, I bought a Herman Miller Embody chair.

    I have to say, this chair has done wonders to my back. I no longer have posture issues like I had before. My back also doesn’t easily get thrown out of place. An added bonus that I wasn’t aware of until I used the chair for a few weeks was I also felt I had more energy at the end of a work day.

    Previous to the Embody I felt exhausted from sitting and working for 8 hours. But after the Embody, I feel more energized after work.

    If you’re in the market for a Herman Miller chair of any kind, I highly recommend finding a local reseller. I was able to save hundreds of dollars by going through my local one.

  • Paid down debt

    This year was the light at the end of the tunnel for many sources of debt for my family. This was true pre-COVID where some student debts were going to be paid off as well as our car payments by the end of the year.

    Due to the immobility of COVID and the privilege of having a stable job, my family and I were able to pay off some debts quicker.

    This has been a great feeling as the weight of debt has been no stranger to my family for a very long time.

    Financially we feel leaner and excited for what being closer to debt free may look like one day.

  • Worked on mental health and self care

    I can’t say this was all that great as some of the issues were residue that carried over from previous years, but this was the year I finally took some intentional steps to address some of the mental health and self care issues that I had.

    I started putting into place regular rituals that included journaling, time blocking and intentional conversations with friends and family about my health.

    I also sought medical help to address some of the physical issues that also triggered my anxiety. I’m in a better place and I want to continue to be in a better place in the years to come.

  • Spent more time being with the family

    With schools closed and many places we visited pre-COVID with our family like museums, the mall or even playgrounds. My family and I have spent more time together. This has led to vegetable gardening in the spring, spending more time with our neighbors and teaching our kids board games such as Settlers of Catan for kids and chess.

What did not go well?

  • Allowed stress to take over a little too often

    While I took steps to address mental health and worked on self care more this year, it was because I let my stress and anxiety get to me for too long.

    Stress and anxiety has never been foreign to me, but physical symptoms were definitely new to me. I started experiencing chest pains which would lead to more anxiety because I was worried about my health.

    As you can imagine it was a bad cycle.

    I really wish I took the time to get help sooner instead of letting the stress go on for so long.

  • Was hard to focus and finish side projects

    Motivation and focus was hard for me as far as side projects went this year. I had ideas, but often I found them stuck in my mind.

    While I didn’t finish side projects, I do feel it was necessary to just be happy with not doing anything but relaxing and lounging. I attribute not working on side projects resulting in a better handle on my stress and mental wellbeing.

  • Sleeping schedule is all over the place

    It seems this has affected others as well. But my wife and I found that it is really hard to get in a healthy schedule for sleep. Not saying our sleeping schedule was great pre-COVID, but it seems with COVID it has perpetuated our bad sleeping schedule even more.

    I know this is an area I want to try to focus on getting into a better habit in the new year.

  • Was more present with family but still absent

    While my family and I were present a lot more. I have to admit I wasn’t always there. It seemed my mind was drawn elsewhere many times throughout the year. Be it due to COVID, elections or just FOMO from conversations on Twitter, I found myself to be absent with my family.

    I knew when I was absent and instead of fixing it in the moment I found myself giving into the absence. This is an area I want to be more mindful of in the new year.

Here’s to taking all the lessons from the good and the bad from 2020 and hoping for a better 2021!

Not time. But energy?

Written on December 20, 2020

People often claim that their inability to do something that they think would be beneficial – execercising or working on a personal project – is due to the lack of time. I wonder, if instead, it could be a lack of energy?