Bryant builds a content personalization system that shows different variations of web content based on visitor segments. Watch as he uses Directus to create a flexible backend for managing segment-specific content variations, then implements client-side detection to serve the right content to the right visitors.
Speaker 0: Welcome back to another episode of 100 apps, one hundred hours. I'm your host, Brian Gillespie, here from Directus. And today should be well, I think it's gonna be an exciting show. My confidence level on this one, just to put that out there, is fairly lower than normal. But today, we are going to be building a website personalization engine.
I went through several different titles for this one. I don't know if that's actually gonna stick when this goes on Directus TV or not. But, what are we trying to do? Well, first, let's explain the rules. If you're new to 100 apps, one hundred hours, the rules are simple.
Basically, we have sixty minutes to plan and build a clone, an application, a website. So that is plan and build, nothing more, nothing less. And then the only other rule, which is the I call it the anti rule, is use whatever you have at your disposal, which I will probably be leveraging, some AI today because I am wading into uncharted territory for me. So website personalization engine, sixty minutes. Let's do this together.
Or it'll, like, publicly laugh at Bryant. Try. Alright. So we're gonna put sixty minutes on the clock, and let's cover this. Alright.
So website personalization, you know, originally, this idea was for, like, personalized landing pages. Like, I know a specific company or target account that I want. Let's create a specific landing page for them. But in the light research that I did before this, which is basically, like, ten minutes of Google, basically, when it comes to personalization, it's more of a segment based approach. So that's what we're gonna sketch out here.
You know, we wanna bucket visitors into a segment and then display certain content for that spec segment to personalize it. So, let's plan out our kinda data model. And, you know, I could leverage, like, some of our direct to CMS starters here. We're just gonna keep this stupid simple super simple. I tell my kids not to say stupid, so I probably shouldn't say that either.
But alright. So as far as our data model, let's flesh out the application. Maybe we do just wanna, like, flesh out what are the actual features that we want out of this specific application and make that less huge. Alright. So we want to have a piece of content.
Great. Directus will manage that for us pretty easily. And then we want to show variations of that content based on traits of a visitor or segments segments that a visitor belongs to. Now, something like this or or even when you get into, like, AB testing, you know, it's fairly easy. I won't well, I won't say fairly easy, but it's easy enough to set up, like, an AB testing code.
If this, do that. If this if else, do that. But, like, the intersection of, like, handing this off to a content or a marketing team and setting it up in code and, like, managing all of that to work together for front end, back end, and making it cohesive, really difficult task. Right? So this is really all I'm trying to achieve today.
We could make this fancier maybe down the the line, but let's let's discuss the data model for this. What are we gonna set up? So I could just call this content. Maybe it's, let's just have a pages collection. You know, this could be like a post or something like that.
And then we're going to have what else? We're probably gonna have some segments. Like, here's the different segments that we want. And, you know, if you were doing, like, a proper system, you'd probably want something like events. Not super concerned with that.
You know, the segments probably have, like, some rules for each segment or yeah. What are the rules? This sort of thing. I don't even know if we'll get this far. Let's just try to wade through this and and show something on the page.
Alright. So let's get into what I've got set up. This is, just a Nuxt application. This is my standard starter for, you know, like, if I was just YOLO ing into a hackathon, this would be my starter. You could see a bunch of commented out code.
But basically, I've got a blank Directus instance, if I can actually get logged into this bad boy. Directus is gonna be our CMS. It's gonna handle all of the back end for us. Dear lord. Why can I not get logged into this thing?
Boy. Boy, oh, boy. Admin example. Password is the password. It's not even up, but that would be why that would be why I couldn't get into the application.
Alright. So I've got Directus set up, in a Docker Compose, just a standard local setup kind of format. And like I said, Directus is gonna be our back end, our CMS. Okay. Great.
Blank slate. Nothing fancy here. We do have templates available for stuff like CMS if if that's something that you're into. And then we have a Nuxt website. Alright.
So let's start building some functionality. And inside the Nuxt website, we've got, like, an index page. So that's what we're staring at here. Alright, so let's add some pages content. Great.
Go in, we'll create a new collection inside pages. For those of you who are new to Directus, what's happening behind the scenes here is Directus is connected to my Postgres database and it is basically gonna mirror whatever changes I make here to that SQL database. And I could connect like a an existing SQL database to this as well. So we have some pages. Great.
Got a collection that's gonna show up here. When I hit new, there's nothing shows up. So we need to add some fields to our pages. And again, like, we're modeling our data here. We're generating an API and we're building a form for our content editors all in one place.
So page needs a title. Great. A page needs a slug. So we're just gonna create a new field called slug. I'm gonna go into the interface settings and make sure this is URL safe.
Do I have my little pointer? Yeah. I do. That's a cool little tool. Occasionally, I get questions on it.
It is called mouse pose, Mac only, I think. Alright. So what else are we gonna have on our pages? We got a title. We got a slug.
Maybe we'll keep this simple. Right? We've got a headline. That could be some text. Cool.
And because I am totally gonna make it easy on myself, we're just gonna call this content. One big rich HTML rich text content block. This probably looks more akin to, like, a blog post than a page. Directus does have that amazing many to any like page builder scenario that's covered in some of our templates but we gotta crawl before we can walk. Alright so we got our pages, lets go ahead and let's just create a page.
Right? This is Brian's page. Brian's page. Cool. Hey, yo.
Why am I talking to myself? Great. Alright. So we got some content. Now if I want to query that via the API, I can go to the directus URL, go to items, pages, and boom.
I could see I have a page here. There's my content. API is ready to go. This is already I've I've got the Nuxt application wired up with, like, a simple Directus SDK client. So we're creating Directus, we're using REST, and then we're providing that to the Nuxt application.
So So if I go in and I do something like this, where we're just gonna create a new dynamic route inside Nuxt and do I have, like, a v t s? Yep. Script set up. Really need to work on my snippets to save time here. And my script at the top guy, when I'm working with Nuxt review.
Alright. So now we want to fetch some of this page content. Right? Because what happens now, I've got this. If I go to Bryant's page, nothing shows.
Yeah. That sucks. We need to resolve that. Alright. So what we're gonna do, we will do const can't type today.
You'll notice I am using cursor here. Directus equals use Nuxt app. And, okay, we've got some auto completions that are not necessarily gonna give us what we want. Alright, so we're gonna get the data. Nuxt has the use async data function or the composable that we're going to use.
If I can actually type that, great. We're gonna give this a key. So, the key, if we grab the routes, is going to be the slug, route. Params. Slug page.
Let's just tag this as a literal. There we go. Thank you. Alright. And then we are going to return directus dot request, we're gonna do read items pages.
Pages. K. And we're gonna filter where the slug, that's right, is equal to route dot params dot slug. K. So we have direct us there.
We're gonna import read items from our SDK. You know, I could potentially, like, import that here and provide that as well if I wanted to, but we'll just do it this way, keep it nice and easy. And then let's see if we can just actually get the data. It'd been a minute since I messed with this. Is this actually going to work?
Are we making a network call? Oh, wait. Use async data. There's that. There's the call that we're returning.
Read items pages. Let's check our network requests. Are we seeing any actual network requests? It is server rendering these. So we are not seeing that.
Probably want to add some error handling. So we'll just add that. If there's an error dot value, we are going to console dot error, error dot value. Great. Do I have any formatting set on this?
Got a little bit of formatting. Alright. Can we see the error? H three error create error. What is going on there?
There's an error. Error dot value dot message. What's the format for this? Create error. We're throwing an error.
Hey. I'm guessing though, just from past experience, this is because we have not enabled any access to that page's collection. Right? So when I do this, I am still using the session token from Directus. But if I open this up in a new browser, we could see, hey.
I don't have any permissions. So I'm just gonna enable permissions for pages. Let's do read permissions, see what we got. Boom. We can actually get some data and wrap this in a nice pre tag to see what we've got.
Okay. Cool. Now let's take this data that we have and we'll add an h one. This will be the page dot headline. And then we are going to check and see what all I do have in this application.
I don't have, like, a pros component. So we'll just do something like this where we have VHtml content. Now if I refresh if I refresh if I refresh, why is it that actually showing? Where's my content? Page dot headline.
How is it that I could see the page content? Oh, I do have it here. Page dot headline. Why isn't that actually showing on the page, though? Interesting question.
Interesting. Definitely. Let's just center this up. Maybe let's max auto, max width, four x up. Add some padding.
Why isn't my content displaying via page? Do we need to wait on the page? Am I really not smart enough to figure this part of it out? Is there some type of error that we're getting paged out headline? I could clearly see oh, yes.
That's why, Brian. You are getting an array here, so we need to transform that. So async data. I think it's here that we can do a transform. Data.
Data. Just the first item. There we go. Alright. There we go.
Hey, yo. Why am I talking to myself? Make sure that you understand what your data looks like before you start trying to mess around with it. We're gonna make that giant. And if we slap a pros tag onto this, pros l g.
I think I've got Telen typography included here so we could see this data. Okay. So we're rendering something out to the page. Great. Now, this is super fancy.
Right? Let's just grab something from the Directus blog to use as content. Here's a post that I wrote. I'm just gonna copy this entire thing. We're gonna go in and throw that here.
Great. Just to get something on the page. Okay. We'll call this context switching sucks for devs. Cool.
Alright. So now we are showing a basic thing on the page. Hallelujah this is amazing this is the coolest thing we've ever built. How are we doing on time? We got about forty five minutes left.
All right so we have a piece of content now we want to show variations of that content for an actual visitor. So how are we going to achieve this sort of thing? And, you know, if we boil this down to the basics, we've got a page. We're going to have variations of page content. Yeah.
We could call this personalizations or page variations. That's gonna be linked to our segments, and this is not right. I do have a PhD in drawing arrows, just not in Figma. This is still a challenge for me. Alright.
So let's create this and I think what we can do is hijack some of the functionality that already exists in Directus for this sort of thing. Going off label here, off brand. So, we will go into our data model. What I'm gonna do, I'm just gonna create a page variations. Yeah.
Naming stuff is probably the hardest challenge in development. You know, we could call this personalizations, but that might make somebody mad. Yeah. I'll just do created at, created by. I don't necessarily need this information.
These are just helpers that you can add. Directus, like, prefix or, like, sets these up for you. So whenever, you save this item or create a new item, it obviously records the user, etcetera. Just some shortcuts. Alright.
So we have page variations. We've got two different collections here. Great. How are we gonna tie these things together? Now, what I can do and what I'm gonna steal is our translations feature.
So if we go to the docs actually, let's go to the new docs. These things are in beta as of now. We're gonna look for translations. Great. We have the ability to translate content and manage all those translations for you.
And if I open this in a new tab, we get, like, this beautiful side by side interface where I could see, okay, here's English versus Spanish or French. And this is like, when we boil it down, like, when I think about it, I'm just now coming to me through my head here, is it basically, translation is a form of personalization anyway. So why not leverage this existing structure? You know, short of, like, the icons and maybe some of the other stuff that is baked in there, I I think it should work. So I'm also going to like, normally, if we were doing translations, you would create, like, a languages collection where you would store all the languages that you wanna translate your content into.
In this case, what we're gonna do is just use, I'm gonna create a new collection. I'm gonna call it segments. You know, we could manually generate the IDs for these or we could use, like, a generated UUID. You know, if I was trying to scale this out, I would definitely be using, like, generated UUIDs, but let's just call this key we're gonna manually enter a string for this. So whenever we create a new segment, we're gonna manually enter in the key.
That'll help us keep things a little bit clearer. Updated at updated by just to keep track. And do we want this segment to be active or not? You know, maybe we set that up on a a Boolean toggle. Alright.
So we got a key for it. Maybe we want, like, a proper name. So we add a name field and drag this down. And what I'm doing here is basically just configuring the actual form that we're gonna use to set this stuff up. Do we have a segment?
Do we have a category? Yep. There we go. Yeah. Again, naming things is hard.
Let's add some icons. Just the designer OCD for me kicking in. Doc. Yep. There we go.
Edit document. And I'm just gonna like actually hide these page variations. So now we have pages, we have segments. Let's create a new segment. Right, I want to speak to developers.
We could say these are for developers, that's our nice name. Directus is also helpful for content editors, so I'll do content editors. Yeah. I wish I was doing this live so I could say, hey, hyphenate or underscore, but let's just go with a hyphen. Fine.
Fine. Fine. You know, I could keep adding these as much as I want. Right? So now we've got some segments, we've got some pages.
We wanna generate these variations. So again, we're gonna reach for the Directus translations interface. And I hope this works out like I think it will or like I hope it will. You can see that we're pre setting the languages collection. Directus is smart enough to know, like, when you're doing translations, you need languages, we can create that for you.
But what I'm gonna do here, I'm gonna open up advanced field mode instead, and I'm gonna go in and I'm just gonna do all of this mapping myself. So we try to be smart and create junction collections and everything for you, but you can take total control of this as well. So here, this is the collection. So we're gonna call this page variations. I'm just gonna use page and we're gonna call this the segment and the collection that we're targeting is segments.
So, I'm gonna set these all up to cascade, so if we delete a page variation or deselect one, we delete that content because we're not going to use these variations across different collections or pages. Alright, so the language indicator field. Now normally this is what shows here right up here. Right? Just the indicator of what this is.
We could use the key. We could use the name. Let's use the name. Language direction. We're gonna ignore that.
Default language is the primary key. Let's let's say I wanna default to developers. And we're gonna start this split. So we'll start open like this. Great.
Okay. So now we create this, and we could show related values. You know, you can even preview the translation content. And I already see one thing that's going to bug the crap out of me as I called it translations. I forgot to rename this.
Alright. So we're gonna call this variations. So it's not translations, it's variations. We're just piggybacking off of functionality. Alright.
Pages. Cool. This is gonna be the what? Key? No.
Segment. We're gonna call that segment. That's the segment. The collection is segment. And I gotta set up this nice cascade again.
Okay. Go through the exact same process all over again. Love shooting myself in the foot Just to make sure we have variations. Is variations spelled correctly? At this point, we don't know.
Alright. So I probably goofed something up already. Did I? Did I not? Page variations.
Page variations. Page page is not found. Oh. Yep. Alright.
So love it when I goof up. Cause more work for myself. We're just gonna start this process all over. Alright. Try it one more time.
Page, variations, Generate the UID. I'm not even gonna go for that. At this point, we're gonna say translations interface. Great. This is gonna be segments.
We're going to use the segment name. We're gonna start with the split open view. And let's control this. Right? Page variations.
This is gonna be page. Segment. Delete. Alright. So definitely don't do what I have done.
Let's try this. See if that works. Doesn't have field page and doesn't have a relationship. And what in the world field page in collections doesn't have a relationship? Why doesn't it it should have a relationship.
Pages, segments, translations, start open. Why doesn't this have a relationship? Well, let's just see what happens when we do this in orally. Translations already has a relationship. Alright.
So we can see here by adding this we get a languages and then we get a pages translations, there's a pages ID, there's an ID. This should work out okay. I don't know what is going on. Maybe I didn't refresh the data model. Key name, segments, page variations.
Why am I not getting this to work correctly? Let's just take a look at our database and see what's happening. 53Edit. 5 3 2, test, Connect. Alright.
So now we're behind the scenes into the database trying to figure out what I goofed up to begin with and it looks like there's some relationships here that got left over that didn't get fixed that are causing problems. Alright. So now with that out of the way, let's try this again. Page variations, we're gonna generate an ID for those. I'm just gonna skip all the fanciness.
And now I'm gonna go in and do translations. We're gonna call this variations. Instead of languages we're going to use segments, we're going to use the name of that. We are then going to set up to use page variations, page segments, segment. Okay.
Now is that going to work out how we want fingers crossed. Let's log in and see what have we got. Okay. So now I get this side by side interface of content editors and developers. Right?
But I don't see anything inside the actual form. So inside this junction table is where we're gonna go in and create our content that is actually going to vary. So in this case, it's just basically going to be our headline and our content. And I can quickly duplicate these. So we'll go to page variations.
I'm gonna say copy headline. We're gonna copy the content. Just make sure you change that copy that we prepend at the end so that you don't, you know, get confused. But with this information set up, now I can get an interface that looks like this where we can say, hey. Great.
Now we've got developers. We've got content editors. Cool. And I can be able to store different contexts here. Context switching sucks.
Great. That's what we'll change the default headline to. We're gonna change this for devs, Context switching sucks for content editors. This content is for editors. This content is for devs.
Alright. So now thinking through our mental model, we've got our default content. And then if we identify a segment, like if the visitor falls into the content editor segment or they fall into the developer segment, we're going to show them different content. Now, what is this actually going to look like? So if I go and like we look at the API now, got my API request, you could see those variations.
One of the beauty, beautiful things of Directus is the ability to use the rest API in a GraphQL like manner. So I could do something like this where I just say, hey. Give me all of the root level fields and also give me all the fields within our variations. So now I can see here's my variations. The segment here is developers.
The, segment here is content editors and presumably on the Nuxt side of it. And, you know, I could rig something up via the API to do this swap for me, but depending on how I'm rendering my site, you know, let's say I'm statically generating the site, if I want to still offer this, I've got to pre generate the payload, you know, pre generate our JSON and store that so I can use it when rendering it. So we're gonna try to do this on the client side. Inside our page level data here, right, we're still getting the same result. And if I add the data back, you know, now we should be seeing our variations, but hey, lo and behold we're not because again we need to go back into our access policies and set that up.
So we're going to allow read access for our page variations and for our segments just so we could see those things. You know, when we're going to production, we'd probably make sure there's some kind of status on these so that, you know we're only showing published pages etcetera, but outside the scope. So now I can see my variations. We're gonna go here and let's just specify our fields, right. It's not content, it is variations of this content.
And now we could see that. Great. Alright. So now we need to translate this content or personalize it in this case. Right?
How do we assign a segment? You know, like, writing a rules engine here would be, kinda challenging with the twenty seven minutes we have left, I would say. But, you know, at the core, we we've gotta have some way to assign the segment. What I'm going to do I I think we're just gonna use a cookie, for this. So Nuxt has a use cookie composable.
Let's just call this the segment key. We're gonna use cookie or you call that segment. Great. And I'm just gonna make this stupid simple. We'll add a div.
We'll flex these, add some gap, make sure that's in the middle, etcetera. And then we're gonna add some buttons. I've got the Nuxt UI library in here. Segment key equals developers. No.
We're not gonna do designers, but, we're gonna do content editors. Content editor. And then maybe we just add I am a great. Alright. Maybe we wrap this whole thing in.
I think it's a u container from the Nuxt UI library. Okay. Yep. So we get a little bit of spacing there, And we can add, just some space between these space y eight. Okay.
Great. And this is probably all part of the same section. Okay. So I am a developer. I am a content editor.
I am a developer's. Great. Again, naming is crucial here. But basically, like, what I should be able to see now if I go into, like, my cookie storage, I can see that segment as well. Right?
So based on this, I'm tagging that person. You know, and we're just explicitly asking. But, you know, we could set up, like, some kind of client side rule engine or, you know, you could potentially do this on the server side as well. Whatever pages you visit, weight those against each other and assign a, you know, if I've got five articles for developers and you look at three of those, then I'm probably safe to say that you're a developer, versus, you know, reading the content editor pages. Alright.
So how do we actually translate this? Right? We probably want, like, a helper function that takes our page data and then evaluates the segment and then, you know, spits out the proper content. So let's just see how awesome AI has become here and see if this is actually worthwhile or I should just probably write it out. But, this wouldn't be fun if we weren't using something like cursor and, you know, something super opinionated or where everybody has an opinion about AI at this moment.
Here we go. Write a let's just describe this. Right? Personalize the page content based on the segment key. Where is this gonna come up with?
Personalize content, page value dot variations. I okay. You know, maybe this would come back. Let's see. Helper function to get the personalized content.
Page variations return page dot that's not really content. Right? We just wanna return yeah. Okay. So I'm probably not prompting right.
Let's see what we can do. Take in the page and the segment key and return a merged page with the proper variation based on the segment key. That's better, still not great. Right? You would probably want, like, a personalized function where it, just basically takes in, the page content and the different segments and the current segment and returns that.
But nevertheless we got our personalized page or we should, right. Great. We can see our variations, we can see the content. If I check-in view dev tools, we go to our slug page. Do we have the personalized page?
Great. That doesn't really Context switching sucks. No. But that doesn't look right to me. Right?
So we do personalized page dot headline, personalized page dot content. Context switching sucks. I am currently in the developer side of things, so it should be showing should be toggling this. Right? So there's something wrong here.
Page dot value dot variation. Yeah. So, basically, what we wanna do is loop through the trying to to do this the AI way and not get frustrated. Loop through the page variations and merge them with the page based on the segment key. Still showing the same thing.
Personalized page. Yeah. Okay. Yeah. Alright.
So this is the final page. Let's define that. The final page. Okay. Then we are going to is this getting smarter now?
For constant of variations, if segment dot key, final page, return final page. What does that do? Why is it why is it still not doing what we want? Page.valuepage.value.variations.developers. Oh, yeah.
That's why. Basically, we need to use, like, a file. Constant variations equals variations. Selected Constant variation is going to be we basically need to look through this array. Variations dot find.
We'll look for the variation. And there we go. Okay. Yeah. So we're getting that array.
That's the problem. So now if I remove this blah blah blah page, Now I have personalized content for folks. Amazing. This is the personalized content engine, website personalization engine. Badabing badaboom.
This is beautiful. Right? So now I can define all of these variations within our actual CMS. Like here's the segments that we want to create content for. You know, I could potentially set up some type of rules engine for this.
And then, you know, on our individual pages, then I can go through and define this content. Now is this a real world scenario? Probably not. You would take this and use something like our mini to any builder where you're building these dynamic pages and within each section you have personalized content for that. But at the very least, hey, this is now we've got, a pretty robust I won't say robust.
This is not robust at all. But it is a a pretty it's a start to a personalization engine basically. That's it. That's all. Now where do we go from here?
Right? I this would be extracted out into a, like, a helper function, so that, like, each page or each block, we would we would call this function, return the content if there is a variation, like, if we have a segment key. Yeah. And we could even go as far as, like, creating a rule engine for this. So let's just continue to beat on AI, which is, honestly not been great so far for this.
Let's say extract this out to out to a helper function that is more robust, maybe. I don't know. Let's see. I'm gonna take a sip of coffee while it's trying to choke that down. The auto completions are not great, but here we go.
Let's see what it's come up with. Personalization. This looks to be a composable. Use personalized page. Here's the page.
Segment key. Update the page component. Here's how we're gonna use that. Personalize page. Use a page.
There is a segment key. Okay. AI. I will bite. Alright.
App utils. Personalization. And I don't know why it's using the is there let's see, like, an actual it's using the composable format for view, but import type maybe rest. Return computed. I mean, to me, this is a I guess this is a this is a composable.
I'm not sure why it's doing that. So we'll stick that there. This is use personalization. This is the name of it. Use personalization.
Again, probably not a strong choice for, like a composable here because this is probably something that you might want to extract out and use, like, across different projects. Use personalization. Use personalization. Okay. Cursor.
Okay. Now that you use this helper, can we have it apply this automatically? Yes. But knowing Nuxt, we should automatically use this. Use personalization.
There's our page content. There's the segment key. Does this still get us what we want? So far, looks like it does. Right?
And the nice thing here is because we're using a cookie, and even though, like, this would be server side rendered, I'm still getting the content that we want. Right? Because it's automatically running a this cookie first before we actually display the content. Cool. Now let's do we have time?
What kind of time do we have here? We got fifteen minutes left. Where do we take this further? Right? Where would we go from here?
How do we set this up into, like, something like blocks, right, where we want to build a page out of the blocks? So for that, we can use the mini to any builder inside Directus. We've got this mini to any builder. We're gonna call this blocks. We don't have any related items yet.
So first thing we're gonna do here is create a hero block. Call it block hero because I like to be obtuse. Alright. The hero is gonna have a headline. It's gonna have a description.
Great. Okay. And then we have a block CTA. Cool. And that is going to have a call out and a button text.
Great. Okay. Now we're gonna put those together with the many to any builder. These are gonna be our page blocks. We're gonna say block CTA, block hero.
Great. Basically, this many to any relationship, it it doesn't necessarily exist, inside, like, standard SQL. Right? So Directus is doing a bit of API magic here. Basically, what what's happening, and we'll just hide, like, what we've got already.
Alright. Hide this field. Don't destroy. Just hide. So we can see what's happening.
We've created these separate collections, and then there's a junction collection here that is storing the page's ID and then we're storing the ID for the item. And then we also have a string for the collection that we're pulling this from. So it's, you know, basically some API magic to string these things together. But now if I go in and I update the page, we could see we've got a CTA that we'd say, this is you should try Directus. Do it now.
Great. There's our CTA. There's our hero. Brian is cool. Well, he's not.
There's our description. Alright. And let's hit save and stay. Let's just look at our page content now that we're getting back. Right.
We're showing two different blocks here, but again, we need to go in and set our permissions. Directus keeps you secure by default. So we're gonna add just read permissions for all this. Again, for production, we wouldn't do this, but can we get to personalized blocks in twelve minutes or less? I need to get my ass in gear.
Alright. Alright so we're gonna go back to our slug here. We're gonna change this up where we have our blocks. And actually we could use like a object syntax as well. Blocks, we're going to have here.
We're going to get the we could get that. And then we're probably also going to have, like, variations within the blocks themselves. Well, this is getting messy. Right? Okay.
So now let's just go back to the page. Variations blocks. I don't wanna do variations. We wanna do blocks. Alright.
I'm gonna pull this back in. For our page render, we're just gonna have to pull that out. And now we could see we got, like, some data for each block. Right? Blocks, items, we're gonna wanna grab the item for each block.
I don't need it. Fields comma. What do we got here? Okay. Well, yes, no, maybe so.
Something is off. We got one too many. How nested did we go here? This one needs okay. Did we get it right this time?
We still did not get this right. Direct as requests. AI is totally screwing this up, and I've had too much coffee to fix this properly. Alright. So we got the block.
We're within the block, we're going to have, the items items, and then we're gonna grab the variations. Where okay. Backup. Backup. Backup.
Love all the formatting. Items. Oh, yeah. This is not going well for me, is it? Fields.
We're gonna grab the collection field. Great. Okay. Now, we got item. If I change this to item, we should see the item text.
Great. And then also we're gonna have variations on that same item. Cool. Alright. But we don't have those yet.
Alright. So let's go in and add those. So now the same way that I created that translation function on, let's say, the page level, we're gonna go through and we're gonna do this speed run style in less than eight minutes. We're gonna call this variations. Great.
This is gonna be segments. This is the collection there. And what are we gonna call this? We're gonna call this the segments. Block hero ID, block hero variations.
Great. Primary key is gonna be the or the primary indicator is gonna be that. We'll set this up. Alright, so now on our block hero I should be able to set up like a variation here except I don't have that content yet. So we'll go to our block CTA.
Oh, no. Block hero. We're gonna copy that headline and description down into the next collection, right, to for our variations so that we can have that specific content. Block hero variations, duplicate. Great.
Now, I go in, we've got our block hero I'm gonna stick up at the top. We have a headline for Brian's cool to editors. Brian is cool to developers. Great. Okay.
And we're gonna create a hero component. View, create a hero component with Tailwind that has two props, headline and description. Let's see what it comes up with. Outsourcing the work here. Six minutes.
You know, we could declare this one good, but, yeah, let's make it fun. Alright. We got the hero component. Okay. So now within the like this page section, I guess, Let's go and call that hero component with the page headline and description.
Context switching sucks. Do we have a oh, no. We don't have that at the page level. Right? We're gonna loop through all of our blocks.
So the, let's do template v four page blocks within the blocks. If the block collection equals the hero to block hero, basically, block underscore hero, that's the name of our collection, we're going to render that out. But now we also need to use the personalized page, page dot blocks, personalized page dot blocks. But low and behold, we're still not changing that content based on that because our personalization is what? At the page level.
Right? So AI, help us in our moment of need. Five minutes left. Change this to well, accept a what a to accept content and recursively merge if there is a variations key within The array within the objects. There's a variations key.
Date. And task. Objects. Let's see what this comes with back. What if just curious.
Alright. Merge variations, current segment, matching variations. Is this to me, like, obviously highlights the dangers of AI? I am on a crunch here. Right?
I don't have a clue. I don't have enough time to, like, figure out if this is actually going to do what I wanted to do anyway. So, you know, great that you can I I mean, I love the fact that I can just, like, quickly POC this, but, you know, it's like a what are we coming back with here? Personalized page. Let's just see what it comes back with.
Blocks zero. So, again, like, is yeah. See, that's goofed up. Oh, and I'm not even giving the personalization content, though, am I? Why is that?
I should be fetching it here. Items, personalizations. We gotta go back into our permissions, block hero variations, access. Save. Are we now at least getting that?
Yes. Okay. So AI did save the day here, basically. You know, before I shipped any of this, I would need to go through and, like, study this in detail to figure out is this actually doing doing right. It appears to be doing right, but are there gonna be, like, dangerous side effects?
But here I could see Brian is cool to developers. You know, maybe we go back in and within this, do we have a does don't like him? Alright. No. He's not.
Neither do content editors. So there is that. You know, the one thing I noticed is we should have, like, a fallback and it should take that fallback into account. So it's not doing, like, a deep merge, but now we could see that content. We could clean this up just to show it out.
And boom. So now we've got, like, page block level data where I could go through and build a page and have segments and personalize that data, for each individual segment. So I'm I'm gonna call that a win. Right? We got one minute fifty six seconds left.
Would I have been able to achieve this without cursor? %. Would it have taken me more than an hour? One hundred percent. Is this still cool and fancy?
Probably not. This is the start to something incredibly cool where, you know, I could go in and on the client side have some type of tracking and some type of rule engine that just, like, consistently con like, creates these different segments or groups of visitor into segments. And if you keep that on the client side, it could be privacy friendly as well. But I hope this was an interesting episode, an exciting episode for you. I've had a good time.
I'm probably gonna figure out a way for us to leverage this somehow in the future. That's it for this episode of 100 apps, one hundred hours. Thanks for joining me. I do roll like the success message. See you guys next time.