Image Loading Enhancements with Cloudinary, Tailwind and Base64 Encoding

Kent Dodds is one of the foremost experts on JavaScript, authoring helpful blog posts and courses on the widely used programming language. He recently shared some techniques to improve his own blog’s image loading experience, which happens to use Cloudinary for several aspects of it.

Becky and Sam from Cloudinary’s Customer Education team talked with Kent, walking through the processes he took to get a 100/100 on the “Cumulative Layout Shift” Core Web Vitals score for his blog. This conversation includes reviewing code scripts to understand his use of Tailwind’s aspect-ratio plugin, Cloudinary’s ability to load perfectly sized images and to handle Base64 encoding, and other important topics.

Sam Brace: [00:00:00] Hey everybody. My name is Sam Brace, and I am the Senior Director of Customer Education and Cloud community here at Cloudinary, and you are about to watch and listen to the latest episode of Dev Jams.

I gotta tell you, I’m really excited for this episode because in terms of JavaScript development, we have one of the, my opinion, the foremost experts in JavaScript development. Joining us as the guest for this episode, Kent Dodds, and if you’ve ever gone to Epic, if you’ve ever just seen overall talks in the space, if you’re even touched some platforms like Remix, you’ve been experiencing things that Kent Dodds has done and.

What’s very exciting is that Kent has an amazing blog and associated community that’s tied to his overall brand. But what’s [00:01:00] great about this is that he has gone through and developed some really great ways to handle what we call cumulative layout shift. And that’s done through low quality image placeholders, making sure that people have content that’s loading quickly and efficiently, but also doing it in a way where they can make sure that they know content’s even gonna be appearing on the page.

So those are all topics we’re gonna be talking about here today in this overall Dev Jams episode. Now, of course, with every Dev Jams episode, my co-host Becky Peltz, who handles overall curriculum management and program development for our developers that use Cloudinary. She’s joining me for this episode, just as we said on every single one of these.

Becky, it is wonderful to have you here for this conversation.

Becky Peltz: Hey, I’m happy to be here. I we’ll be learning a lot here. There’s a blog that we’ve all read that is, just wonderful at blending inspiration to solution. You [00:02:00] read through it and it just flows out this great idea and then how to solve it.

And then we get to see how he uses Cloudinary to to as a big tool in getting that solution.

Sam Brace: One thing that I love about it, and you articulated it well, is that the one thing that’s nice about having a guest like Kent on here, because as we said, he’s an expert in this overall space, is that he also is very good at being able to show the step by steps, the understanding, sometimes historical background information you may need to know, which I know we appreciate as educators, but it really does help to have a holistic view of why you might wanna be doing something or what this person experienced with the overall project.

Becky Peltz: Yeah. I know he’s an educator and I think that, programmers, we’re good at breaking down steps for machines, but I think when you get into educators, you get people that can break it down for people and it’s so much appreciated.

Sam Brace: Completely agree. So before we bring Kent on to be able to talk about all the great work that he’s doing [00:03:00] with his blog presence, and of course because me and Becky work for Cloudinary, there’s gonna be some Cloudinary things that we’re gonna talk about in this overall space.

But we do wanna make sure that you guys know that if you are the first time listener, first time watcher of this overall content, you can always go to Cloudinary dot com slash podcasts. And that’s where all of our podcasts for the two programs that are managed by the company. Are going to be. So if you ever have questions about what past episodes, what topics have we gone and covered, they’re all going to be in that overall space.

And of course you may decide to listen to or watch some of the programs on certain services like YouTube or Apple Podcasts or Google Podcasts or Spotify. We happen to be in all those different places. So if this is your first time here, welcome and of course we are very happy to have you here. And we wanna make sure that you know where you can be catching all of these episodes down the road because this won’t be the last conversation we have.

But it may be definitely [00:04:00] one of the best, cuz as I said, we are so excited to have Kent here today. Let’s bring Kent on and let’s get into the start of our conversation. So Kent, welcome to the program.

Kent Dodds: Thank you so much. And you’re right. Those were very nice words like you said at the start. Thank you.

I appreciate it.

Sam Brace: And also very true, very true. People that are not completely familiar with all the great things that you’ve done, all of the work that you did to get to the spot, give us a little bit of historical data. Who’s Kent and why

Kent Dodds: are you here? Yeah, so I live in Utah with my wife and four kids, and it’s a very snowy day out today.

It’s been a very fun winter if you enjoy snowboarding. And yeah. So I have been an educator since, like even before I graduated. I’ve been teaching people the stuff that I know, whatever it is. And I worked as a full-time engineer for [00:05:00] a number of companies, probably the one most people recognize is PayPal.

And then I decided to go full-time teacher because I was I just enjoyed that more and I can’t do it all. Went full-time teacher. That’s right around the time I built testing JavaScript and then I built Epic React. And then I actually built my website and lots of the stuff that we’re gonna be talking about today.

And then I, now I’m working on Epic which is everything that I know about the web. And this topic will certainly be included in that. And yeah I also did spend about 10 months working on remix, the sign behind me and the framework that I use to build my website as well.

Yeah I do plenty of stuff in the open source space and I blog a lot. So that’s me. [00:06:00]

Sam Brace: Kent, is that it? I mean that

Becky Peltz: Is that all?

Sam Brace: That amazingly historical data that you have there, and it shows the overall space that you’re in. It’s where being an educator, but also understanding a lot about how the web works, a lot of things that we’re talking about, of course, you’re tied to the React community, the JavaScript community. So it’s where you’re touching a lot of different places, but it’s where to say that you’ve, you have some experience working in this other area, so what you’re telling people to do or not to do there’s some credence to that.

Kent Dodds: Yeah I would say so. People follow my advice and then they thank me later. And then I don’t know if people follow my advice and it doesn’t work out. They just haven’t mentioned anything. But I do have experience in this space shipping apps to millions of users. And I’ve been developing for the web for almost a decade now.

So it’s yeah I’ve got some stuff to say. [00:07:00]

Sam Brace: When I’m seeing comments popping up from, people are saying like, he’s also the author of React Testing and off and a thousand NPM packages.

Becky Peltz: You’re being modest, in other words.

Sam Brace: Regardless of how people feel or not feel about this, it is to say that I’m very happy that you’re here today.

And what I’d love to be able to understand, so now that we can see this, you have your blog, you have your website, so that’s What took you to the space that you started to say yourself. I wanna start working on some of the things that we’re gonna be talking about today as I mentioned earlier, cumulative layout shift, low quality image placeholders.

Why did you start to see the need for some of these things that we’re gonna be talking about?

Kent Dodds: Yeah, that’s a great question. My original website at, if you go to the web archive and look back in like 2015, the website was basically a white screen with text that says, I’m too busy to build my [00:08:00] website.

Here’s some links to my Twitter and whatever. And then at some point I decided, I would like to have a better online presence. And so I wrote my site in Gatsby and statically generated it. And that’s when I started writing being really active on my blog. And one of the cool things that I got out of Gatsby was it’s built in support for image processing.

So it was able to take my image, turned it into an SVG. And so when you landed on the page, you would see an SVG as a placeholder, and then the image would load in and it looked awesome. There were a number of problems with that not at least being that processing took a lot of time.

And so deploying my site, even like fixing a typo, would take 20 minutes. It was the worst. I hated that. And so you could add a bunch of caching and stuff, but yeah, that was not fun. And so when I for that and various other reasons, I decided to [00:09:00] rebuild my website. And it was this really big effort that I did.

Was that last year or maybe the year before? And yeah, in the process, I didn’t want to lose that really nice loading experience cuz my website has images everywhere. But like the biggest, of course, is my blog. Every blog post has a header image, and I wanted that loading experience to be as good as possible just because when I decided I wanted to make a professional website, part of the reason was because I wanted to illustrate that I really knew what I was talking about.

Especially when I am saying, “Hey, come learn how to build awesome websites with me”. If my personal website’s no good, then okay, you’re gonna teach me how to make like a website like yours, that’s garbage. I don’t want that. So my personal website needs to be very good. And so avoiding poor user experiences I’ve had cumulative layout shift.[00:10:00]

And that basically that, if you go to a website and you think see things popping in that’s bad cumulative layout shift. You basically want it to poof, there it is, and nothing moves, other than things that may be animated. Nothing moves. Yeah. That’s like in animations are a fun subject that we could talk about later.

But the idea is you don’t want things popping in place. And images are one of the biggest culprits of bad cumulative layout shift as well as banners that pop up that those are the worst. And yeah, so that, that sort of thing. Or ads, of course, like I, I don’t do any ads, but pretty much anything that you do that happens only on the client can cause cumulative layout shift. And the fact is that we’re not server rendering images. We’re server rendering an image tag that tells the browser how to load the image. So you can technically server render an image if you use Base 64, and we can talk about that. I [00:11:00] actually do that.

But for performance reasons, you typically don’t want to server-render your image like that. There are special considerations that you need to take into account when you’re talking about an image heavy site like mine.

Becky Peltz: Yeah. You definitely don’t wanna see big chunks of things moving around and at the same time, there’s a lot of options for those chunks. And I think, you have to pick a really good option. For, we’ll see how you figured it out. But just popping up a bunch of little tiny thumbnails isn’t really gonna be a solution because that’s gonna be just distracting.

Yeah, the user is looking for a continuous experience. It’s okay if it’s, if it changes, but it has to kind of transition. It can’t be like “boom” kind of effect. And I think as people who write frontend code [00:12:00] are really dependent on the device or the browser that they’re working with, they really have to like, understand it and work with what it can do.

And I think probably why Google is the one that is telling us about cumulative layout shift and how you’re gonna maybe lose your SEO ranking if you don’t, get it working.

Sam Brace: Now we’ve talked about cumulative layout shift, but I also know that’s an area that Google has started to look at when they came up with the concept of Core Web Vitals. That’s something that I started at least hearing about a lot back in 2021, I feel was the first time when someone said Core Web Vitals or Web Core Vitals or whatever they wanna, mix, match.

But something called me about this. Was that also part of the reasoning for it? It was tied to Core Web Vitals and the scores that are associated with that?

Kent Dodds: So I actually do have metrics for my Core Web Vitals, and they’re actually even public. You can find it on, if you [00:13:00] scroll down to the bottom of my website, there’s a transparency link.

I think it’s, do I call it transparency? I, it might be mission or something. Yeah, “My Mission”, if you go to that that’s my transparency page. And on there’s a link to both my analytics as well as my metrics for my site. So anybody who wants to explore that a little bit. So I do keep track of the Core Web Vitals, but I never look at it.

For me, especially since I’m not actually selling anything on my website, I’m selling myself. And the investment that you’re offering me is your time. That’s really it. And also I suppose your email address. Of course I link to to courses and stuff like that, and I do sell those, but not on my personal website.

So the reason why my personal website needs to be a good experience is just like I said to illustrate that I do know what I’m talking about. I know how to make really awesome [00:14:00] experiences for the web and also because it’s it’s like a game of code golf. Like you just, it’s fun.

How good can I make this experience? And for businesses where you are selling something on the site, it can make a drastic impact on your bottom line based on how quickly your application loads and how confident users are that your application is doing what it should be. That it’s capable of doing whatever it is that you’re selling.

So if users land on your site and things are bouncing around a lot, it really reduces their confidence in your ability to provide whatever it is that you’re intending to provide.

Becky Peltz: Yeah, a website is a reflection of your product. If you’re doing a lot of crazy weird stuff on your website, maybe the product is a little funky too, just leave it alone.

Kent Dodds: Yeah. I sometimes will pick [00:15:00] restaurants based on how good their website is.

Sam Brace: Yeah. I actually have done the exact same thing, Kent, where I’m like, oh, that probably is a reflective of the overall service that I’m gonna be getting.

Kent Dodds: And maybe it’s not like it, it might be, it might not be, but it doesn’t actually matter cuz what matters is, did you go?

And so yeah, it does impact the customer’s impression of you.

Sam Brace: Absolutely. And when, and I think what’s also important, like whenever I thought about the Core Web Vitals as well, is that they’re normally done because Google is looking at it from a sense of trying to make the best user experience.

It’s not based upon trying to hit some score that’s arbitrary and doesn’t have significant value to it. They’re looking at to make sure that when we’re saying this has XYZ score to it, or 123 score to it, it’s indicating some factor of quality as overall associated. So I think that’s what [00:16:00] you’ve ultimately done with this overall experience to be able to provide these low quality image placeholders, be able to do the work to make sure the layout shifts aren’t constantly shifting.

To say that you did, to increase the quality. And I think that’s one thing that people should look at from an episode like this, is that if you’re trying to increase the quality of their overall web presence, a lot of the practices you did here who are directly applicable to things they could possibly do for their content as well.

Becky Peltz: Yeah. Yeah. They’re unleashing tons of crawlers on the web and these things need to act fast. And if those crawlers are waiting for images to load before they can figure out what the content is, that’s gonna be a problem for them, too. It works both ways. It’s like machines are sensitive to it as humans.

Sam Brace: So what I wanna jump into, so I’m, what I’m showing here is the blog post that kind of inspired this overall conversation. So if people are [00:17:00] saying, I wanna follow along, you just have to go to the and make sure that you’re looking for the “building an awesome image loading experience” post that you put out in late 2021.

But you can see here this video that you created is articulating exactly what you ultimately have as the result of this effort, where it’s making sure that the image has a place, it’s showing a low quality, blurred version of it, and then the full image will eventually come in, and that’s what we’re calling the low quality image placeholder.

Am I correct about that overall summary? Yeah.

Kent Dodds: That’s the basic idea.

Sam Brace: Okay. So looking at this overall situation here, I think the first section that we can see that you’re touching upon is the overall layout shift. As we mentioned, we don’t want it where you have text and it’s jumping to be able to bring in the overall space for the image.

We want it where you have the layouts make, it’s almost static. It’s where things should [00:18:00] be in certain places at certain times. It looks like you were able to do that with Tailwind. Talk to me about this overall plugin that you had here that was helping with the layout shift.

Kent Dodds: Yeah, sure.

The principle is aspect ratio. So you don’t know necessarily how big the image is going to be a lot of the time. But you might know the aspect ratio of the image. So because the, you might say, I want the width to be 90% of the viewport. The viewport could be any number of pixels. But you know the aspect ratio of the width and the height.

And Tailwind actually now supports aspect ratio as a built-in feature of Tailwind. So you don’t have to include a plug-in anymore. But the idea is just using that class name and it’s, I should also say that aspect ratio is a built-in feature of the browser that Tailwind is just using.

But yeah, [00:19:00] so that aspect ratio just will say, “Hey, I know that the image isn’t here yet, but when it is, this is how much space it’s going to take up” relative to how wide it is or whatever. And so then the browser can say, “okay, I’ll just leave that much space for that image”.

And so when the image shows up, it just pops in place and doesn’t have to move anything. So that’s actually a really, even if you’re not doing the nice placeholder or anything like that, that by itself is really useful. It can be kinda tricky if you don’t know what the aspect ratio is going to be.

So if you’re thinking about Instagram and you got pictures that are all sorts of different, you’ve got this grid and there are pictures coming in all over the place that can be tricky. The solution to that really is to just store the aspect ratio as part of the data for the for the images that you’re displaying so that when you server render or when you end up starting to render those images, you can include that because it, there’s really no other way to solve [00:20:00] this particular problem.

That’s precisely what aspect ratio CSS property was created for. And it is definitely better than having pictures pop in place cause even if we’re talking about that sort of grid of photos, you’re gonna have one pop in and then one above it pop in. And so that shifts this one down and they’re, they’ll just be going all over the place.

It just does not feel good. So aspect ratio is the solution to content layout shift for images.

Becky Peltz: And I noticed you linked to the article on setting height and with on images is important. Again, because for a while people went away from that. There was, initially height equals blah, what width equals blah.

And then the browser could figure out the aspect ratio that you were going for. But people stopped doing that. And a lot of it probably because we went from, just a desktop to a mobile and it didn’t really make sense in that respect, but this is a really good point here.

Sam Brace: What it also seems like it’s directly tied to the [00:21:00] next point that you raised here when you’re working on responsive images. Because aspect ratio, of course, is based upon the actual ratio. It has nothing to do with pixel width or pixel height. So when we’re saying we want it to be, let’s say, a three by two aspect ratio that we’re gonna be able to allocate the space for, that’s gonna be three by two for tablet, for desktop, for mobile, or maybe you need it to change, but it’s indicating what it should be based on these different areas.

So I think it’s leading us into the conversation about what you’ve done here with making sure that everything you are doing when it comes to this effort also is tied to responsive design as well.

Kent Dodds: Yeah. So if I’m on a desktop with a huge 5K monitor with this ridiculous resolution, then I can load an image that’s, really high quality and, pixel perfect.

And that’s awesome. The problem is that’s just a ton of pixels, and that’s a [00:22:00] lot, a very big image. And then if I shrink that down to something that I can see on a device and I’m using the exact same image either way. Then I am, basically what the device is doing is throwing away a bunch of pixels that it doesn’t need. It can’t display that many pixels on the device. Anyway, so it’ll look really nice and crisp, but there’s a lot of wasted download there. And the web platform comes in clutch for us again with the sizes and source set attributes on the image tag.

This was something new for me when I was working on my site. I’d never used these properties before. But the basic idea is these are configuration options that say so we’ll start with sizes. It’s a comma separated list of basically you could think of it as a tuple. So you’ve got an array of first the media query that should match and [00:23:00] then the width of the image at that media query.

And I can say for small sizes, then this is how wide the image should be, for bigger sizes, this is how wide and so on. And so I’m going actually in the blog post here, I’m going the opposite direction. Big size, this is how big or how wide the image is gonna be and so forth. I only know that because I know that the CSS that I’ve applied and so I added this later on and I just pulled up my site locally and looked at how wide the image was at different breakpoints, and then just said, here’s the size of the the image or the width that it’s gonna be here.

So then the source set says, here is the URL for when the screen is at this size. So if the screen is this big, then this is the URL to get that sized image. That allows you to really fine tune which image [00:24:00] is loaded for a given screen size which avoids the wasted bytes and ultimately results in a much faster loading experience.

Becky Peltz: Yeah. And with your sizes, because they’re always concerned, really they’re really focusing on width rather than height. You’re gonna see that the size that gets assigned is really based on the width. So you, you have a width of 50, then you’re gonna get 50 and width 30, 30. So feeling that.

Kent Dodds: Okay. Yeah I’m not sure if there’s a way to switch it so that it goes by the height, because if you wanted a horizontally scrolled thing or something, I don’t know, people come up with funny things. I don’t know what the world of VR says about all of this stuff is very width centric or, the way that we build most websites.

But yeah, this works out well for 99% of people.

Becky Peltz: Yeah. Yeah. No, totally.

Sam Brace: So in looking at this, so now scrolling down to the post, you can [00:25:00] see that now that we’ve understand like source and source set that we covered at this point, we can see how this is being done for a blog post like yours, where we’re looking at the overall URLs that are coming from here.

And of course now I’m starting to see Cloudinary and for his first case. So talk to me about what’s ultimately happening in this situation, because I can see that you’re declaring the whiffs as we’ve talked about, but then you’re also doing certain other things that are tied to this overall place that looks to be at least longer in URL compared to what you have for the initial example.

So talk to me about that.

Kent Dodds: Yeah, sure. My Cloudinary URLs, this is one of the things that I just love about Cloudinary, is the capability to transform the images on demand. And what’s cool about this is because I have q_auto and f_auto, this will not only give me well, and then of [00:26:00] course I have that w_ that specifies the width of the image that I want.

But this gives me not only the right size of image, but even the right quality and format based on whatever browser is requesting this image. Which is just awesome because we have a bunch of different formats whether it be a GIF or a PNG or a JPEG or a WebP or AVIF, all sorts of formats that various browsers support.

And it’s impossible for me to know at development time what browser is going to be requesting this, cause it’s literally all of them. And having Cloudinary be able to dynamically serve the proper image at request time is awesome. And it should be noted also that we do still have the regular source, attribute and that I just sent to like the middle between all of these sizes.

So if your browser doesn’t support the source set and sizes [00:27:00] attributes, then sorry, you’re just gonna get like a middle of the road thing here which is probably your experience on the entire web. If your browser is that old, it’s gonna be a pretty poor experience anyway. But but yeah, so I have a bunch of different sizes based off of what made sense for wherever I’m rendering this image.

This one in particular is the header image that I have on my blog.

Sam Brace: And then looking at this so I can see here you have very clear widths that you’ve declared when it comes to this, and as you said, like your source in here is in between the range that you have between 280 and 3,100.

But how are you getting those sizes? Is that just saying double the next one and then going it up? Or is there tools or utilities that you’re using?

Kent Dodds: Yeah, I wish there were tools and utilities and there. There may be now. But when I was writing this I didn’t know of anything, so I literally just pulled up my site, opened up the dev.

And then just [00:28:00] resized it every now and then, and just said that, that looks like a pretty good size. And then I grabbed what that size was and I have the next block of code here is the get image props that accepts what I call an image builder. It’s just a special little function that allows me to generate these URLs, cuz who’s gonna write that URL by hand, not me.

And then I can specify the widths that I care about for this particular image and the sizes, as well as any additional transformations I wanna make. And with that I can very easily just say, here are the different widths that I want to be concerned about for this particular image.

And these are the sizes when those widths matter. And yeah that ends up working out. If you scroll down a little bit further, you can see an example of using that utility. It ends up [00:29:00] being a relatively simple way to to manage this. Though there are some tools that I mentioned at the bottom of the blog post that can make this process even easier.

I’m not sure exactly how they accomplish that, because I feel like every image experience is gonna be actually a little bit different. But yeah, this is what I came up with and it’s been running on my site for quite a while now, and it works great.

Becky Peltz: Yeah, and it’s nice that you’ve codified it because if you decide you wanna change those widths, you just change a few numbers here in your code and you can spin up a whole other set of responsive images.

Kent Dodds: Yeah, mhmm.


Sam Brace: Now, one thing that, I saw a comment just come through here and saying “this approach would work potentially amazing for videos too”. Based on your experience, do you feel like that’s correct, or do you feel like there’s any caveats to that statement?

Kent Dodds: Yeah, I actually I’m guessing I haven’t looked in this, but I’m guessing that videos also [00:30:00] have a source set.

And sizes props. I can’t imagine why they wouldn’t. And Cloudinary also has support for on demand video as well. So I can’t imagine why you wouldn’t use this for that. I don’t have a lot of use cases for video on my site. Normally I just embed a YouTube or something like that.

Cuz yeah, I just don’t do it enough. But yeah, it sounds like that would be a pretty good solution for that as well.

Sam Brace: Excellent. And yeah and shout out to the community for being able to address things like this as we’re be going through this overall process too. So it seems like some of this was inspired, I know you mentioned Gatsby earlier, but also this was inspired by what Unsplash has been doing with your placeholder process. Talk to me about this and maybe what did you extrapolate from what Unsplash is doing to be able to keep going down this process with your own blog?

Kent Dodds: Yeah, sure. Unsplash [00:31:00] is like probably the pinnacle of image display on the web.

Like they, they do just a silly amount of work on displaying images. And so when I moved away from using Gatsby and I still wanted to have this nice load loading experience I tried to figure out, okay, so how do I have a nice placeholder that I used to have with Gasby and I thought about the SVG thing.

But SVGs sometimes look really funny. They do not. I mean they’re very small and that’s quite nice. And they, server render fine which is also nice, but yeah, the images can sometimes or the placeholder can sometimes look very odd. And so I I’ve seen Unsplash and Medium and others will have this placeholder that’s just like a blurred version of the image. And what I discovered as I was reverse [00:32:00] engineering what they were doing, I would look at what was server rendered, and it turns out they server render the primary color of the image. So they do some pre-processing of the image, determine what the primary color is. And then they also and that’s what ends up being so server-rendered.

Then another thing that they do, they pre-process the image to create what’s called a blur hash. And this is actually, it’s an open source thing. You can go grab it yourself with the blur hash is like 30 characters max of just random, seemingly random characters that somehow, it just is magic to me.

But they somehow represent a blurred version of the image. It’s like total magic. I don’t understand how this works.

Becky Peltz: Base64, a Base64 version of a blurry image that they can move in quickly, but it has to be a small string .

Kent Dodds: Yeah. It’s actually, it’s not even a base 64, because they’re using characters that are not [00:33:00] base 64 characters.

Some cool algorithm that somebody figured out. And what they do though is they feed this into a canvas and then the canvas can draw out the image based on that that blur hash. So what’s interesting though, or unfortunate is that canvas doesn’t server render. There are probably people doing some mad scientist stuff to make canvas sort of server render in some ways.

But yeah, that, that’s just not a thing. There’s no server rendering of canvas. And so that’s why they have their three-step process of first server render the primary color, and then show the blurred version with blur hash and then the final image loads. Now, this is actually not a big problem for oh, and the other thing is the blur hash library is not small.

It’s not huge, but it’s not small either. So that’s another thing to consider when we’re talking about making things fast and load as little [00:34:00] JavaScript as possible and all that. This isn’t a big problem for Unsplash because lots of the time, people will show up to the site and then they’ll click on images.

And if they’ve already got everything loaded, then we’re not server rendering those images anymore. Now we’re rendering them on the client side. So you actually will not see the full primary color displayed like we see here when you’re on Unsplash, because you typically are, you go to and then you click on an image and you, they already have the blur hash right there, so they don’t have to server or render the the primary color.

So for me though, lots of times people just land on my blog post. In fact, most of the time they do. So I didn’t want to have this three step process where we’re displaying the primary color first, cuz it just, it felt wasteful and a lot of the time the people wouldn’t even see the blurred version anyway, cuz Cloudinary’s CDN is very fast and so we’re gonna get the image anyway.

And so having that three steps just didn’t make any sense [00:35:00] to me. Yeah, that was honestly just a fun learning experience. I didn’t actually use any of their techniques myself because I didn’t want to to do the canvas approach or the primary color thing.

Sam Brace: One question I have about the primary color thing.

So if I go back up to the overall script that we’re showing you here, and you can see that we have these transformations and you have the background call on this case, is that the primary color coming through in that situation?

Kent Dodds: Yeah, that’s a great question. So I think that is just for transparent images.

Like I have a couple blog posts that have a transparent background and I decided at some point that they just look funny, to be transparent. And so I can’t remember what color that is. But it was just like a good background color that’s generally use or good for anything that has a transparent background.

No there’s no I’m not like determining what the primary color is and [00:36:00] putting it in there. That’s hard coded.

Sam Brace: No, but I still like this approach though. Cause it’s a flat color. It’s showing this is where something should be. So it may, it makes sense why you would do this type of a transformation.

So it may not be exactly like what we saw with Unsplash, but it is showing similar purpose.

So moving on to you. So now we’ve gone through the overall process here of talking about what you’ve gone and done and we can break down some of this, but we’ve touched upon Base 64 encoding. For those that aren’t fully aware of what we even mean when we say something like that.

What is Base 64 encoding and why would you even wanna do something like that?

Kent Dodds: Yeah base 64 encoding is just a way to represent binary data as a string. And like in, in particular as like a string that’s using characters that we recognize. But the particular [00:37:00] nicety of base 64 is that it can be used as the source attribute for an image element.

It can actually be used as a source attribute for a lot of things. There’s another place on my website, it’s the Call Kent podcast where you can actually record yourself asking a question and that will save to my database. And then I record my response later, and then that turns into a podcast episode.

It’s actually very cool. And I use Base64 encoding to set the source attribute of an audio tag so I can preview what they’ve recorded and stuff. So you can use Base64 to encode just about anything into what is a readable string and it’s not necessarily really small.

But interestingly, that that audio file that I create when people record themselves in the Call Kent podcast, I tried saving it to my database as binary, and I then I tried saving it to my database as Base64 and Base64 [00:38:00] was smaller. So I probably did something wrong, but I was, because I was very surprised by that.

But that’s how it’s saved in my database today is I’ll save it as Base64. With that the binary data that I want to turn into Base64 is a blurred version of the image, my placeholder. I want to turn that into Base64. And the reason that I wanna do that is so that I can render my blog post with that Base64 hard coded as the source attribute so that the browser doesn’t have to actually make any request to display that placeholder image.

And yeah, that’s the entire reason that we’re doing Base64 at all. Because if I what’s cool with Cloudinary is I can just say, “Hey, give me an image that has a width of a hundred and give it the effect of a blur of a thousand”, whatever that unit means. I don’t know what it means. I tried a bunch of numbers and that worked.

Becky Peltz: Best way to figure it out.

Kent Dodds: Yeah, exactly. And then and I [00:39:00] also specified the format as WebP, just because this is my server doing it. So I can’t rely on whatever browsers are requesting this. Anyway, I make a fetch request on the server at runtime to this, that gives me back the image data, which I then encode with Base64 and then set as the source property of my image as the background of the image that’s going to be loaded later.

So the drawback of using Base64 versus the blur hash is Base64 is 10 times bigger. In, practice it’s 10 times bigger of, a couple characters is actually not a whole lot. Like you look at the size of this blog post, it’s, it’s just a little drop in the bucket, but it still is not the best.

And so I wish I could avoid this. But for the use cases that I have, it’s definitely the best option.

Becky Peltz: It’s just like a lot of [00:40:00] channels on the web only can deal with text, if you want to put an image in a email or something, sometimes it has to be Base64 encoded.

Kent Dodds: Yeah. They don’t want to load remote stuff

Becky Peltz: Yeah.

Kent Dodds: But this wasn’t the end of everything because one thing I noticed was, and you scrolled to it for a second there. The blurred image looked really bad, like very pixelated, because what I did was I took it only a hundred pixels, so it was a hundred width. So not a hundred pixels, but it was width of a hundred.

And then blurred that, and then I upscaled it to 10x, a thousand pixels width. And so that just made it look, even though it’s blurry, it looked pixelated, just didn’t look very good. And luckily there is an awesome filter that you can apply to a div. So I put a div on top of, positioned absolutely on top of this image where the backdrop [00:41:00] filter to set a blur.

And then so I blur it from Cloudinary and then I blur it further from the browser to give it.

Becky Peltz: You have a tiny blur. You expand it and then you make the browser blur it. So that’s.

Kent Dodds: Yeah. Yeah, exactly.

And I actually, now that I say that I didn’t think about just saying, “Hey, Cloudinary, give me a small image and then I’ll just have the browser blur that myself”.

But maybe I could have tried that. But it’s working now, so why bother?

Sam Brace: And that’s one way we look at it is it’s like not everything always has to be a hundred percent Cloudinary. It’s where with CSS, other things you can come up with amazing results. And this is a proof of that. So we’re a piece of the pie.

We’re not the only pie that’s there. So that’s good.

Kent Dodds: Now I want pie.

Sam Brace: You can see the immediate difference here too. Like you’re, you can see like the rings of this are very distinct. It’s, it almost has a muddy look to it with the amount of moving you’re seeing there. And then when you did the work that you did, everything’s [00:42:00] smooth.

It’s very hard to tell even from the background what I’m looking at here. Which is the point of blur. So it’s a good, it’s very good what you did.

Kent Dodds: Yep. That, was actually that, that worked out really well. But it still wasn’t quite what I wanted because what I was looking for was you have the blurred image and then it fades into the finished image.

And what we had at this point was you have the blurred image and then when the actual image loads, it just takes its place. And that doesn’t look too bad. It’s fine, but I wanted it to fade into place. This is tricky because there’s no API in the browser from HTML that says, “Hey, apply this class when it’s ready to go”.

Of course, there’s a JavaScript way to do that, but there’s no HTML way to say, “on load, do this thing”. And what I had to do was I, and of course [00:43:00] like already we’ve gotten a couple of things in here that I’m like, yeah, I definitely want turn this into a component so I don’t have to do this all over the place.

So I made this blurrable image component, and so the code that we’re looking at now is an example of that blurrable image component. Where you passed the Base64 URL. That’s the blur data URL that we see as the prop there. We have our aspect ratios there as well. And then we have our image, the element, that you’re supposed to be rendering here and there’s the get image props there as well for doing our different sizes and all of that stuff.

So the actual implementation of the blurrable image component is a little bit further down, and this does some pretty interesting things.

Becky Peltz: Yeah.

Kent Dodds: Yeah. Sorry. Did you have a question about the usage though?

Becky Peltz: No, I just said this is cool. I [00:44:00] like how you did this.

Kent Dodds: Yeah. So the blurrable image component it takes that image, it takes the blur data URL, and then the rest of the props that it takes are just whatever else you can apply to in an image element. We’ll just pass those along. And so what we have to do in JavaScript because we, there’s no HTML way to do this as we have to maintain some state to say whether or not the image the final loaded image is visible.

And then I use that visible value to determine what class names should be applied. So this is all React’s nice and declarative model where we can re-render, and now the, here are the class names that it should be now. So you’ll notice on line 33, I’m cloning the image element that they gave me.

So , we have the react element that’s the image element that they created. I’m actually going to not render that directly and instead create a new one that’s a copy of that. That I have a reference to that’s the ref prop there. [00:45:00] And then I have a class name that’s going to be all the classes that they provided.

Plus I want to transition the opacity so I can animate that. So I can transition in and then I set the opacity to zero if it’s not yet visible. And then we’ll get to that use effect here in a second. But then where I render, I need to render the div. I’m gonna put all of the the rest of the props on that.

So I guess those that rest is not the image element, it’s the div element props. So yeah, I, I render a div around all of this to keep them together. If there is a blur data URL honestly, I shouldn’t make it so you can render one of these without that, because why would you use this component if you didn’t have a blur data URL?

But if that does exist, then I will render the blur image. So that is the source is the Base64. The class name is gonna have the same [00:46:00] class name as the image that you’re providing, so it has the same sizes and everything. And then the alt text because we care about screen readers.

And then we have that backdrop blur you URL to give it a smooth blur. And then next to that we render our JS image L and then the no script image there. So in case the, this is very rare but if somebody has disabled JavaScript on my site, I still want them to be able to see the images. And so we’ll just render the image as it is and it will work.

And I’ve tested that. That works. And so yeah that’s the basics. Now the trick is how do we know when we should remove that opacity zero class name? And so that’s what the use effect is for. If you go a little bit above, like in the middle of the blur image component, there’s this use effect where we say first we do some early returns, like if the ImgElRef, if we don’t have a current [00:47:00] DOM Node of that image, then that’s unexpected. We’ll just return that, that will never happen. But, I mean it could, and we don’t want bad things to happen if it does. So I guess and then the jsImgElRef.current.Complete. That .current is just a DOM Node reference to the image element.

And so .complete is a property on an image element that says whether or not that image is finished loading. So if we have finished loading, then we’re just gonna return. We’re all done. We’ve done this before, it’s fine. And it then we say add event listener on that image element, Load.

So when that load has finished, then we’re going to set visible and we’re putting that inside of a set timeout for a good reason that I can’t remember, and I probably should have wrote a code comment to explain why we’re doing that. I remember putting it there. I just don’t remember why I did it.

Just putting it on the next ticket to the event [00:48:00] loop for some reason. I just can’t recall why that was necessary. So anyway, that, that’s a basic idea. We’re fundamentally we’re just saying when this image has finished loading, then let’s set it to visible so that it will fade in. So it’s actually a lot of work just for the simple fact that I wanted to be able to have it fade in rather than just magically appear.

And that the bulk of this component is for that particular feature, we could probably remove everything from line 14 to line 41 if I didn’t care about that. Yeah.

Becky Peltz: When you do have timing considerations here cuz you’re rendering really two images. You’ve got your blurrable image and then you, in the background, the other, the real image is loading and you need to know when it’s done before you can do your transition. So you do, you are working with some things that you have to think about there.

Kent Dodds: Yeah. Now what’s kinda interesting about this is I ran [00:49:00] into some problems. First of all, it makes me a little uncomfortable that I require JavaScript for my images to be seen. So if we have to wait until the JavaScript shows up before we can actually get that opacity zero class off, cuz we, we render that opacity zero class on the server.

So you will not see this image until React does its thing and I can say, okay, re-render without that class name. That makes me feel uncomfortable. And it actually played out in in production where I had some sort of error with my site where the JavaScript errored out. And so this code never ran, and so people could only see the blurred image only the stuff that was sever rendered.

And the no script stuff on line 54 doesn’t work in that case because scripts are available, they’re just, they failed to run. And so I don’t really like that too much. And I just moved [00:50:00] on and it was fine. And this only happened once and so it wasn’t a really big deal.

But it does make me feel uncomfortable that I have to wait for JavaScript to load and then be parsed and then executed before we can actually remove that visible zero or opacity zero class name. Yeah, that’s just unfortunate because the image could actually have finished loading before the JavaScript has even been loaded itself.

And so we’re showing a blurred. A blurred placeholder when we could just be showing the full image and that would be a lot better. On top of that, if the browser has already cashed the image and you just go up and hit refresh on the page you’re going to see the blurred image until the JavaScript is evaluated and stuff.

Where, what I would prefer is that you don’t see a blurred image. So what our status quo is now is you always see a blurred image and you’ll see a flash of blurred state and then you’ll see the [00:51:00] full image. And I would much rather say if the image is in the browser cache, it should just instantly show, I don’t even care about showing a placeholder.

And so I left it this way for a long time and then like two months ago, you all reached out to me and said, “Hey, we want to talk about this cool blog post”, and in the back of my mind I’m thinking, “Oh shoot, there’s that one thing I don’t like about this”. Two days ago, two days ago, right before we did this, I spent a little bit of time investigating.

This this loading experience to make it a little bit better. And so that’s the next section here is fading faster. Yeah, I said, and really that’s it. That was how I ended my blog post before. And then I added, except now that it’s 2023, I decided to improve one more thing, and that’s to make it fade faster, to solve this problem of what if the JavaScript fails to load?

What if something goes wrong? And the fact is because html doesn’t support any mechanism for updating or for saying, I want to fade this image [00:52:00] in. We have to do it in JavaScript. But, I don’t want to tie all of this logic into that particular bunch of JavaScript that happens within the react hydration and all of that.

I would a rather just have a little bit of JavaScript because it’s really not a lot that says when this load thing happens, just remove that class. And so that’s exactly what I do in theory, this is as easy as it should be, is you just add an on loan prop. I realize there are a lot of people who are looking at me right now and saying, “you’re doing inline JavaScript, you’re a joke”.

“That’s even worse than inline styles”. And it is. This is the quintessential, like perfect use case for something like this. It’s the simplest amount of JavaScript I can imagine for for this type of use case. I could also do render another script [00:53:00] element that does the same thing, but I don’t know, look at line 5.

That’s easy. There’s nothing complicated about this. Unfortunately, there is something complicated about this because React does not like inline JavaScript like this and it will not render it will not render these prompts and instead it will give you an error that says you need to use the on load prop with an actual function.

And so that is annoying. That’s really unfortunate.

Becky Peltz: There’s nowhere.

Kent Dodds: Cause now I’m like right back into the React thing and I have to wait for all of React to hydrate and all of that. So, I did a fair bit of work to make this this work. That is a little involved and I don’t think it’s necessary for you to dive in.

You can look into the commit that I linked to a little bit below to dive into how I made this work cause it is kind of complicated. But at the end of the day, I was able to make a really awesome experience where if you’re on the page and you hit refresh, [00:54:00] so the image is already in your cache, you do not see a flash of loading state.

And it just it instantly just shows the image. And I think that is a much better user experience. Yeah, you, if you click on that, yeah, you can see on the left side it’s flashing. Each one of them is hitting the refresh button at the exact same time. But the left side is flashing the blur state and the right side, you don’t see anything like that, so much better experience. Some people actually comment on this and they say, “I actually like seeing the blur state, cause it shows me that it refreshed.” And I’m thinking “You’ve been conditioned, my friend. That’s wrong. You don’t like it. You don’t like it.” So anyway, there you go. That’s how I did nice placeholder and an awesome loading experience on my website.

Becky Peltz: Yeah.

Sam Brace: Amazing.

Becky Peltz: It’s so interesting how there’s such a battle with wanting to use JavaScript to help you make things work, but then JavaScript takes long to [00:55:00] load, so for performance reasons you don’t wanna use it. Yeah. It’s kinda like you’re torn.

Sam Brace: So, a couple questions for you, Kent, about this overall thing. So, obviously we’re using React for a lot of the things that we’re showing in this case, but could you take similar concepts that we did here or maybe identical concepts and apply it to other frameworks, let’s say Vue or Angular other things, or is this like where unless you’re using React, this is impossible.

Kent Dodds: Yeah, that’s a good question. There’s nothing in here that I’m doing that is exclusive to React. This is all web platform stuff. Arguably it might even be easier in other frameworks because of that on load thing that I was talking about.

React just really, doesn’t want you to do that. Like I said, I could do an inline script or a script tag that does the same thing and that maybe I’ll switch to that. Because you can’t actually the content security policy doesn’t work very well with inline scripts JavaScript or attribute scripts.

Which, [00:56:00] yeah, so I should probably change it for that reason. But yeah, actually at the bottom of the post there, I have that little Ps there’s this unpic image component that is a framework agnostic implementation, very similar to what I’m doing. They actually don’t do a Base64 and instead use CSS gradients to accomplish a blurred version of the image.

It’s very interesting and they have implementations in all sorts of different frameworks. They also support a lot of different image CDNs, including Cloudinary and others. Look, I wish this existed when I was building mine, but now I have this cool blog post where I can explain how it works.

Becky Peltz: Yeah, no it’s just a neat, watching you come up with a solution in this, and I’ll just share too, that like the Cloudinary React SDK does have a placeholder plugin that you as it kind of starts out blurry and it turns [00:57:00] full resolution while you’re watching it. But again, you’re loading somewhere JavaScript to make that happen.

Sam Brace: And I, I actually love the shout out you’re doing for the unpic side of things because I can look at just the contributor to list here, and there’s some really awesome people that are tied to this. Looking at Zach, who’s tied to Eleventy here, our friend Elad who’s tied to Stackbit, like there’s a lot of good minds that are putting contributions into this particular thing.

I agree it’s a great place to be able to start handling multi framework imagery and responsive aspects of it. So it’s great. So, one question that did come up in the community that I wanna address here, because a lot of things that we covered here, of course they’re, in my opinion, I would say advanced topics.

You’re doing things where you’re almost like optimizing what’s already been optimized with some of the things that you’ve gone through, this process stuff. But, let’s say that I’m a fairly new JavaScript developer or someone thats new to web development, [00:58:00] where would I be going to learn how to do more of these things? And I’m not trying to give you a softball like, “Hey, queue up Epic or React and all the great work you’re doing there.” But please do. But in the same sense, like where, is there any spaces where people can be getting to better understand what’s happening with the web, particularly with JavaScript development that you’ve come across that have been helpful?

Kent Dodds: Yeah, I have a blog post about experience and getting experience as a web developer, cause this is a very common question, how do I get better? And the answer sounds pretty obvious. You get experience by having experiences. You really just have to you, you can spend all day on Twitter. You can spend time on YouTube watching videos. You can spend, buy a really great course like Epic React when Epic Web comes out, Epic Web. And that’s all good. You should be doing those things some of those things. [00:59:00] But really you don’t get experience until you have those experiences.

I strongly advise just spending a ton of time working on actually building stuff. And subscribing to newsletters is good for keeping up. I’ve got a really great Discord community that you can come in and keep up with what’s going on in there. Staying involved on Twitter and stuff, that’s also really good.

To be involved in that. So all of these things are useful to give you a sense of what’s going on in the ecosystem. But then you have to take that and actually build something.

Sam Brace: A hundred percent, and I’ll plug your Discord community. I’ve become a recent member of it myself, and I think it’s a great place to be hearing about these conversations, but to further your point, it’s where if you hear something that kind of tickles your brain and you’re like, oh, I wanna learn more about this, then yeah, do your job to learn about it, [01:00:00] but then get your hands dirty and get into it.

And that’s the only way that you’re gonna be able to grow, in my opinion as a developer. You, you have to if you always say good writers write a lot, the same thing, good coders code a lot. And it doesn’t mean that every line you write is gonna be beautiful, but sometimes it will be, and it all comes experience.

Becky Peltz: I think its sort of like any kind of like an athletic event, if you wanna be prepared for it, or if you wanna prepare for it, you just have to do a lot of it, it sounds like every day you have to dedicate time to massaging that and building it up.

Sam Brace: Excellent, Kent. I’m inspired and I, and of course we’ve already shown the blog post extensively to all the places that people can understand what’s happened and be there. I’ll also point out in, gimme a little bit more detail there too, but you have a GitHub repository that is focused on just the overall blog presence that you have here, and I’m sure that a lot of the things that you have that you’re showing here [01:01:00] are available through this overall repo. But what, like, why did you ultimately decide to expose everything you have for your website in this repo?

Kent Dodds: It’s easier. Yeah. So my, my content is actually inside of the website itself. So there’s the content directory and that’s all my pages, all of my blog posts, everything is in there. And I do that because the, it’s just a lot easier to manage the contributions when I have like typos and stuff, people contribute I have hundreds of contributors to my blog posts through that mechanism. And then my, having my site open source just makes it a lot easier for me to answer people’s questions. They’ll say, how do you do this? And I’ll just say, here’s the file where I do that.

And so yeah, the entire site is open source and it I’ll I’ll also mention that my website is not your typical developer portfolio. And if what you’re [01:02:00] building as a developer portfolio, do not use my website as a template because it is way over scoped for what you’re trying to do.

And that scope brings along a lot more complexity than you need for your site. So start use somebody else’s because I’ve got three SaaS products that I or three things that I could turn into SaaS products on my website. That you definitely don’t need on yours.

Sam Brace: Completely fair. And it, it’s good to get people of those caveats. I completely agree. And I think we’ve also one thing I always ask before we end one of these conversations, Kent, is where people should be going for more information. I think we’ve made it pretty clear, is your main portal for all things that are tied to you.

But is there any other places where you find that you’re more active? Are you more on Twitter or LinkedIn or other places? Or if you wanna get like the the latest that’s coming from you? [01:03:00]

Kent Dodds: Yeah. I’m most active on Twitter and I always share stuff to the Discord community. They typically get the exciting stuff first.

And then the, my mailing list that you can find, just, scroll down to the bottom you can or just sign up for an account there and you’ll be put on the mailing list as well. But yeah I’m doing remote workshops and stuff like that I, yeah, I recommend yeah your signed up looks like, cause you, you signed in, but yeah, so that, that little image on the right there turns into a form if you’re not signed in.

Okay. So yeah, the, that’s probably the mailing list is the best way to not miss anything, for sure.

Sam Brace: Excellent. Kent, once again, I’m inspired even past what I read of the blog post, getting to hear your introspective review of how you [01:04:00] got done, what you got done, and also getting the business case of it.

So, keep up the good work, Kent. Obviously there’s lots of people that are tied to the communities and the work that you’re doing, but we love what you’re doing here at Cloudinary, so keep it up.

Kent Dodds: Thanks a lot. I appreciate that.

Sam Brace: Excellent. So Becky, I had wanted to ask you.

Becky Peltz: Yes?

Sam Brace: What is our big takeaway from this? There’s a lot of things that are bubbling up my mind by what’s yours.

Becky Peltz: I think that Cloudinary needs to create an e_kentdodds effect. So we don’t have so much JavaScript. His process is just wonderful. And I think the effect is something that anybody could appreciate. And he does use one of our effects, the blur effect. But then he has that little bit of magic in it that gives you something before, and then it transitions into it. Yeah it’s definitely something if you’re putting images on your site, think about something like this or [01:05:00] use this.

Sam Brace: Yeah. It’s one of the things that we’ve seen other great guests talk about some similar stuff, like when we had Brad Garropy on, he was talking about cumulative layout shift and being able to understand it.

But it’s where this is kind of taking what Brad did which was kind of creating a simple placeholder for it and really doing a lot with it. Being able to tie in the blur effects and then being inspired for the different places on how we can maybe incorporate background colors as we saw so, and being able to evaluate what is the right choice for your overall presence.

But it is to say that the more you can create an optimal experience for the visitor or the user or the person that’s diving into your content as Kent showed, you can really do it in a really fun way and make sure it also helps out your presence from how search engines and others see.

Becky Peltz: Yeah, and I think too, like just the idea he got inspired by what he saw on Unsplash, that you could see something on the web that you like and you can [01:06:00] actually take it, tweak it, write your own code for it and make it even better, so it’s great to, to be aware of that inspiration out there.

Sam Brace: I completely agree. And talking about further inspiration, Becky, we have future and past episodes. They’ll always be at So if you took something away from a conversation that me and Becky just had with Kent, please make sure that you’re checking out other episodes that are happening to be in the space.

And of course, those episodes are gonna be on all the places where you typically will like and subscribe to podcast content such as YouTube, the Cloudinary Academy, Spotify, Apple Podcasts, Google Podcasts. There’s so many out there, but it’s where we do have hopefully our presence in those different places, wherever you like to consume content.

And similarly, I recommend continuing the conversations about this overall content in the Cloudinary community. That’s gonna be at [01:07:00] and as you can see, when we take a look at this, this is going to be where you have lots of forum based tools, but also if you’re an active Discord user, we do have a lot of members of the community that are also having more real time conversations in that space.

And so if you’re a forums person, if you’re a Discord person, if you’re both, it gives you options to be able to continue the conversations about what you’ve just heard about in our conversation with Kent and have that possibly affecting the way that you’re building out your next software development project.

Becky, before we let everybody go, any final words, any final thoughts?

Becky Peltz: Yeah, I just, it’s amazing what’s going on in the community and to meet somebody like Kent Dodds who is so involved and in into so many things. I think I’m thinking, I’m gonna go sign up for his newsletter, let’s just say.

Sam Brace: Becky, thanks for being a part of this as always. And thank you, all of you that are listening and watching this DevJams episode on behalf [01:08:00] of everybody at Cloudinary, thank you, and we hope to see you at the next DevJams episode, and where we’re we gonna profile another developer that is building inspiring, innovative, exciting projects, and of course using Cloudinary for an aspect of it. Take care everybody. We’ll see you soon.