Transcript
Let's see. Okay, we're streaming. Welcome everyone. I'm a bit overwhelmed by all the people. It has been five years, I think, since the last time we were in London, in a much smaller room with much fewer people, and it's awesome to get back here and see all of you. We have a pretty packed programme today, but it's also packed with a lot of learning, and we're not doing any Q&A, you have to actually speak to the speakers afterwards, in fact. But yeah, restrooms: through the open door on the left, not the elevator or the emergency stairs, but the door on the left. Yeah, right, yeah. There are fire escapes, there's green signage. This is only for people here, not people watching on YouTube. But yeah, thanks Codehouse for hosting us, fantastic. Hope you have grabbed food and drinks; you'll be able to grab more. There's a little, like, chair game, so in between the talks, if you feel like standing, that's where the people are, now you know. But yeah, there are also benches you can also see, in their own style. But yeah, I shouldn't be talking, because we have, as I mentioned, a packed programme. I'll give the mic over to my colleague Simeon, who you might know from the internet. And I will get back to being a producer. Yeah, thank you again for coming.
Yeah, good, thank you. Yes, on the internet, and there's a bunch of great speakers, more than one person, a bunch of great talks. I'm going to run through the names. So Youssef is going to be speaking tonight, Jono from Roboto Studio, Evelina as well, we've got a talk from Toby at Even Six, and then I'll be closing out with a talk as well. So I don't want to hog the stage too much tonight. Let's get straight to the first one, come forward and get set up.
Actually, while this is getting set up, it's interesting: you've got a migration to WordPress, a migration to WordPress to headless, a migration from WordPress. Where my mind is at the moment, actually, as well: it's the next course. I run the learning programme at Sanity, and it's the next course that I'm currently actively writing. My head's there because I'm literally writing a big migration script from WordPress, so if there's learning to come out of that, I would love to hear it, what's happening there. If you have struggled to migrate into a headless framework, I'd love to hear what the challenges are there. There are so many different data sources to come from with legacy systems, and it is a challenge. So yeah, just trying to gather as much information on that as we can. That's my pitch for what I'm working on next, and I'm going to hand over.
I'm a software engineer. I have my own company, Spaces and Tabs. I do web and mobile development, and I'm here today mainly to tell you a story about how we shipped the website for Women Techmakers. There is a lot to unpack in the story, so I am going to focus on the basics here. It's mainly going to be a story about how to get the basics right, and how getting these basics right gets you a lot of the way there. So Women Techmakers had an old website. I also built it for them; the founder of the community is my wife, so I'm her guy. The old website, as you see at the top here, and the new website is down here. When you look at it, you might not see much: it's just a UI uplift, there isn't really much happening. But actually, under the hood a lot of it has changed to support this new thing we built.
Just a bit of context. The old website was basically a week's project. We sat down together, and in a couple of days got a template using Gatsby. The template was mainly a blog, so it had an about page, maybe a small blog, and we used it mainly to showcase some of the local meetup events that were happening at the time, and that was when the community was small scale. Right now the community is much more than that. So we have different pages, such as directory pages, which are a speakers and founders hub, so it had some interactivity such as search and filtering and things like that. We added a whole lot more than a blog, so you have different types of blogs, different types of content, different types of conferences. So when we had a look and decided to uplift the UI of the website, we also had a look at what we're using in terms of content management, how our content modelling was doing, and the tech we're using to build the website.
So a good question is: why start over? It looks like a fairly simple UI uplift, so why go through the process of doing all that and building it from scratch? Well, on the content side, the first thing is our content model wasn't really flexible. We had all these pages, and every page had its own, what you can think of if you use Sanity as, like, a schema. So you had a conference schema, a blog post schema, a knowledge hub schema. All of them are almost the same, and we are just changing a bunch of fields here and there. So it's not ideal, it created a lot of duplication, and obviously, something that's built in a weekend and then evolved really rapidly, it caused a lot of headaches. And soon enough, Gatsby, we stopped developing as well. It was great when we started, but we're using static site generation, so the more pages we had, the slower it got, and obviously once Netlify acquired it, things got a bit stale, so it wasn't moving or something. And the final nail in the coffin was Contentful got really expensive. We were on the free plan, and it was working for us until they limited the content models, how many content models you can have, and suddenly we were exceeding that limit and looking at a $300 bill per month, which is really quite expensive. So, it's not Contentful's fault, but we really needed to rethink how we model our content.
So I'll talk a little bit about how we planned the migration. The first thing is we looked at the templates we had. A lot of it was actually duplicated pieces and duplicated structures everywhere. Let's say, for example, you had a podcast and you had a blog. Both of them had a piece of rich text, and then in the podcast you had an embed for the podcast player. So why do we have two different data models for them? It wasted a lot of resources and added a bit of a headache in managing it on the content side. So what if we actually took a step deeper into it and figured out what these templates are built from? When you looked at the templates (this is not a real screenshot, like a real image, but just an approximation), when you look at the template, it's actually a bunch of smaller models, UI components you could say, that actually make up the template. So what if our content model is not necessarily mapping to a template, but instead our schema is just the UI components, and then we just render them to form a template, similar to this? Simply, even if you have a big template, or you are building any kind of interactivity or a feature on your website, ultimately it boils down to a body with a bunch of sections in the middle, right? Your hero, your piece of content, and then maybe your related articles. That's just one example. So if we shifted those templates and moved them to a content editing concern, not a development concern, not a content structure concern, we don't care about it when we are rendering a page. And with that in mind, that means when you have different variations of the same component, it's not necessarily a new template anymore, it's just tweaking a few fields in the content schema or the models that we have.
This is a very simple example. It might not give you the full idea, but let's assume these are two separate templates, right? Both of them have an image, have a title, and have a piece of text in the middle. In the old website, what we'd have done is have two distinct content structures for them, named them differently because they're used in different places, but in reality all we needed to add is really a boolean flag to mirror it, right? So these are part of why we just finally decided we needed this rebuild, to update all our content schemas and migrate them away from being duplicated based on what variations we have, into something that's more flexible that we can use to build templates on top of.
The next step in our migration really is moving away from complexity. So as I mentioned before, we're using Gatsby. Gatsby forces us to use React, but do we actually need React in this? We probably don't. We were perfectly happy, like, the new website is perfectly happy with HTML, CSS, some JavaScript in some places, but mostly HTML and CSS, to be honest. And even the CSS, I used Tailwind. I'm a mobile developer, so don't blame me. And yeah, do we actually need static generation? I mean, I'm torn on that, because, well, spoiler, we used Astro. So even with Astro we can do static site generation, but it actually proved more headache than it's worth, because with every update you'll need to rebuild the website, so you need to build some kind of hook mechanism or something to update your website every time you publish something, which I'm sure Sanity has great plugins for, hooking into Vercel or Netlify or whatever. But also the other headache is previews, because now you need to build your website but have some kind of server-rendered version of it to support previews. So if it's already up on live, you might as well just serve it to the people.
So yeah, with this in mind, we actually started on the implementation. Instead of just a fresh UI update and calling it a day, we actually built it all from the ground up. As I said, we used Astro, and I love Astro, I've been using it for a while now. From someone who doesn't really develop websites a lot, Astro is just really a breath of fresh air. Just HTML, CSS, no fuss, very well documented. You can build, like, everything is in their documentation, it has really good plugins, and the best part about it, like I mentioned, is no locking your UI framework in. So you're not locked into React, you're not locked into Vue. If you want them, you can add them; if you don't, you still have your own HTML. They have a hybrid mode as well, so if you want to statically generate you can. Spaces and Tabs, my own company website, is actually Sanity with static site generation, but for Women Techmakers we ended up using server-side rendering. So that really fit well with us because of its simplicity.
And obviously, that's why I'm here: we used Sanity for content management. The big wins for us in using Sanity were actually the Sanity Studio. There's a whole load of customisation on it that we added, and for me at least, I felt it's really nice and really productive to have my schemas and everything defined in the same place where I actually do the rendering and write the code to render all these components. It really fit well with my mental models and how we're working. And the query engine that Sanity has actually really helped us build this kind of page builder, because you don't know the parameters you are targeting and what you want to fetch, because every page can have its own UI components. So it worked really well with how we query things, and I will give you a sneak peek of how we actually do the querying and how we avoid unnecessary calls later in the talk.
So we are building a page builder on Sanity. How do we structure this schema? I think I gave a bit of a brief overview early on. Mainly, we are focusing on UI components. We're not building templates, we are building UI components, and from that, templates become a separate concern for content editing, and we'll see how Sanity makes life easier in that as well, so we can bridge that gap. But I'll just walk you through some of it. I'm sure it's basic knowledge, but these basics are actually what set the project up for success and made life easier for me as a developer and for the Techmakers team to edit their content and migrate it one by one.
First thing is easy: just enforce your rules. If you have any fields that are optional, or should be optional or not, make sure to add your rules in the schema, and that way content editors can get these nice warnings when something goes wrong, and you, as a developer, trust your own data that you are fetching, because you know that you put your rules in there. You know that when something is required, it's required, and it's not going to go missing. That saves a lot of the headache, and it's something that we really lacked in the old website as well. We had some random values, everything was almost optional, so you had quirky behaviour in how things rendered.
The other thing is: really be descriptive. You have name, you have title, you have description. Use them to tell the content editors what exactly this is meant to do, especially in every field, so they have an idea of what to write. Obviously you have your previews, but sometimes they're just filling in their content early on, and you don't want any misalignment.
Next is: choose sensible values for your preview. What I mean by this bit here: Sanity, the Studio, will pick up some default values for you if you don't define it, which is a good start, but this data is contextual in where it is and what you are trying to build. So for example, if we are building a page here, I'd like to know what component I'm using or what component I'm editing, so you customise it to make sure that the preview gives you that title, for example, here in the header. Using sensible values for previews helped us make content editing an easier, smoother experience.
And shared new UI elements should have a schema for them. Even if you don't have a design system, you still would like to share some elements of UI here and there, and if you are already defining a schema for your UI components, you don't want to go about duplicating how a button looks, for example. This button can have a background, or can have a border, or can have an icon, and all these are shared, and you want to standardise that across all the UI components, so it's easier for you to build and support that on a schema level, so content editors can reuse that and can update it once and it goes into all your UI components, rather than just copying the same fields over and over across the components.
And limit the free-form inputs, especially for things that have specific values. So again, Sanity Studio and your schema definition will really help you in getting dropdowns or checkboxes or radio boxes for whatever you need. Again, it's all about removing any unknowns in the content editing journey, and as a developer, trusting the input you're getting. Ultimately you are getting a string, but if I know from the editing side that I'm only getting this subset of strings, I can easily reason with that in my code and avoid any unnecessary edge case handling.
And finally, do yourself a favour, do everyone a favour: your content editing team, give them previews. It's really easy to get the iframe up and running. For us, there is a bit of logic to manage the perspectives and the tokens you are passing in to get this up and running, but once it is up and running, it's really helpful to avoid having a staging environment and a production environment, for example. You can leave everything on draft, it renders the draft, and people can share feedback, and Studio is really amazing to have comments around, and it keeps the collaboration going.
So with all these in mind, and updates, we ended up having a structure similar to the one on the left. We have one level, which is shared UI components, such as your buttons, how your links look, any requirements. So images: we have a requirement that every image should have an alt text, for example, and to filter that through, we use UI components directly in the other page blocks, I call them, or visual blocks. So for example, there is a form block or an author block or a header block. These reference the UI components and have their own fields. Usually, once you clear out the images, clear out the UI components, what you're left with is what type of text you are using: is it normal text, long text, or portable text? It doesn't really leave you much variety, which is good for standardising. Even for a page builder, you don't know what you are rendering, so you need to standardise as much as possible the contract between the content and what you are building.
And this is what a page looks like now. So instead of having a template with a bunch of fields to make a template, a page just starts as an empty array, and you just fill it with the components you need, which is similar to any page builder you have right now. Like if you go to Squarespace or whatever, similar drag and drop, and then you fill each component individually. The good thing about this is it just uses the designs and styles and the components that the content editors are familiar with, and they don't need to recreate them, and it's an environment where we can do more updates, because of how extensible the Sanity Studio is.
So with that in mind, that's the Sanity part of it. How do we consume this data from Sanity? I'm not going to go into a lot of detail about how Astro integrates with Sanity; this is just a brief overview of the journey of a request today. We get a request. We only have one layout now, because we eliminated all the different templates, all the different layouts. Everything that's configurable now is coming from Sanity as a configuration by the content editors and whoever is maintaining the website, and there's build-time configuration coming from environment variables and things like that. So it simplifies a lot of the code. We stripped out all the layouts that we had, all the different templates. It's only a single template, and this is where the head, with all its metadata, gets rendered. It makes it so much easier to reason with, especially around SEO, around Open Graph meta tags and all these things like that, and obviously makes it easy to put scripts in as well, like if you're tracking with Google Analytics or whatever. The page layout just references a block renderer, which basically takes whatever you fetch from Sanity and renders it on the screen as visual components, and you end up with a nice list of visual blocks, and there you have the screen.
A little bit on how we call Sanity. The initial version of what we had basically fetched the page from Sanity, got your references, and then each reference resolved itself. So you're making subsequent calls: if you have 10 components on the screen, you are making 10 plus one API requests, which will consume your Sanity credits really fast. So actually, the trick that we did here is to resolve the first level of references when we are fetching the page. That's why I was talking about having a flexible query, because it just makes life easier. Resolving that first level of references gets you almost all the visual components that we need. There are a few visual components that have references to other visual components, and these can be resolved after, but there are not that many. So best case scenario, on almost the majority of the pages, you have just one call to the Sanity API. Worst case scenario, you do the n plus one, but these are pretty rare for us, so we're happy with that kind of performance.
Another thing is separation between these visual blocks, so they don't know about each other, and they don't know about the UI components they are referencing. Everything calls the renderer recursively to render any children that they need. Again, that way, it's one easy way to standardise everything and make sure that you only have one source of truth on how things are rendered, instead of copying that visual implementation in different places.
So that's really everything of how we shipped it. There is a lot more detail. I'm happy to answer any questions about that. You can find me and ask me any question about Astro later on, but for now I'll just leave you with what's next for the website, with most of the updates that are coming next, hopefully we manage to do it, or I will manage to, later, for them. It's going to revolve around content editing. So remember the screenshots I showed you earlier where the page is just a block of items, right? Content editors still need to manage and work around templates. So one thing to add, I think, is initial value templates: basically a fancy button that creates a blog page that will basically create a page, add all the relevant blocks for them, so they can just fill in the content and don't have to worry about what visual component type they need to use here or there. An extension to that is improving the duplication behaviour, because we're using references, every page, when you duplicate it, carries over the references, which is not ideal if you are content editing and just want to duplicate a blog post and just update the content; you end up overwriting. So again, another duplicate button that will actually work on duplicating all the references as you go will be helpful for content editors. So that will be coming soon to their website. And finally, visual editing. I just saw it got recently merged into the Astro integration, so hopefully we'll get into that, because again, with the previews that we have, that will make content editing a lot easier. And that's it from me. Thank you so much.
I have a written version of that talk, so we can link that up. Thank you.
So hi everybody, how's it going? I'm Jono from Roboto Studio, and today we're going to be talking about five key takeaways from websites that we absolutely loved building. So let's start by talking about what is Roboto Studio. We are a development agency that is hellbent on providing the best editorial experience that you can get right now. What is the best editorial experience? For us, it's Next.js, Vercel, and of course Sanity, and we've basically been building the exact same website for about three years now.
So let's start with number one. Number one: migrating old websites. If anybody's actually migrated a website here, you know how much of a nightmare it is, and so I wanted to talk about things that you actually can do when you are migrating them. Something that's really, really difficult is internal links. Migrating an internal link from content to content is very difficult. Taking images is incredibly difficult as well. Working with old tags for images, that's another thing. And then finally, pulling existing categories from different web pages is really, really tricky. However, something that we don't talk about enough is web scraping, and the power of actually using that.
So let's talk about one of our clients, Jam. They had 4,500 products, they had 200 blog posts, and out of those 200 blog posts they had interlinking, internal links into those products, and now all of those products have changed categories as part of this migration, and it's incredibly tricky to be able to get that content and move it over to a new website. With that being said, we managed to get 100% migration coverage, and you know what's crazy about this? We actually managed to do it because of web scraping, rather than actually having access to the back end. Something that people forget about very, very often is the way that you can actually use web scraping and integrate it directly into Sanity to be able to populate content. And with that being said, we're on to number two.
So we're going to talk about integrations now. When we talk about integrations, a lot of people are going to think just web applications and how they integrate into Sanity, but there's a lot more stuff that you can actually do with it. I'll give you a quick example now that we've done recently. With YouTube, you may have an incredible channel that you're putting a lot of content out on, and you actually want to integrate this directly with your website. Now, if you did this in the old days, what you would do is you would sit there and you would copy, paste, put it over. It's a real pain in the ass, but it's very, very open to human error. There's no end of times that I've put something over and it's actually not spelled correctly, or it's missed out a punctuation mark. But the beauty of integrations is that we can actually interconnect YouTube with Sanity and create a brand new document type, so you have your YouTube videos directly in the Studio. It's pretty neat. The other benefit that you have when you actually pull this data into the Studio is that you can actually enrich that data with Sanity. So for example, if you know that a YouTube video actually has a lot of interesting stuff about, well, let's talk about integrations, you can actually have related blogs that talk about integrations. It's really nice how you can start building on top with these content layers and all these fancy bits and pieces.
And with that being said, I want to talk about cron jobs and API integration with our next clients. We had, pardon me, the Techaro project, which was essentially integrating HubSpot with Sanity. Now, a lot of people actually use HubSpot for marketing, for analytics, all that fancy stuff, but the usual experience of HubSpot is somebody goes into HubSpot, and the most likely thing they want is the forms, because they're really good for funnelling people down to convert. But the experience to actually get that form into a website involves going to HubSpot's embed form, taking the little iframe, putting that on your website, hoping that it doesn't have any, like, iframe hijacking or anything else like that, and it's not the best experience. So you can actually directly integrate the API from HubSpot into Sanity, and so we did that for Techaro. We integrated their HubSpot accounts, so whenever they build a PPC campaign or something that we want to try and convert, we essentially have the ability to just reference the form from HubSpot. We run a cron job to basically pull this data, so it's always fresh, and it's always the latest and greatest forms that they create.
The other interesting one about this is Wistia. If anybody's used Wistia before, they do have an API available, so you can pull, for example, podcasts, you can pull videos, all of this fancy stuff. But the one thing they don't have is transcripts available. So if you were to, for example, pull a podcast, you probably want to also get that transcript. The interesting thing that you can do, and what I would always advise doing, is actually run a scraper with it. You can take that API request and you can basically stack that with a scraper and get all of that rich information and put it inside of Sanity. It's worth mentioning, though: split these two things. Split it into editable content, and split it into content that's basically being pulled in from an API, because you don't want to do destructive stuff on editable content.
And I want to talk about number three today. Number three for us (don't worry, there's only two more): set and forget SEO. Set and forget SEO is where essentially you're using the structured data that already exists in Sanity to essentially populate JSON-LD for Google. This is incredible stuff, because realistically you've already got all the structured content from your content management system, and Google essentially just wants this content that you've written in a format that it can basically take and run with. The beauty with the brand new thing, the Sanity TypeScript generation, is it works directly hand in hand with the schema-dts TypeScript tool, if you've seen this about. If you use those two in combination, you can essentially get all of that data from your Sanity Studio and combine that with all of the data that Google actually wants to see.
For example, we work with a company called Futurepedia that did exactly this. They wanted to generate pillar content, and the pillar content was very, really focused, like pin focused, on organic SEO. So when we were building that organic SEO content, we essentially populated all that JSON so that they could try and rank for things like AI productivity tools, AI image generation, this kind of fun stuff. The other bit that was interesting about this particular project was the fact that we were using, again, scrapers to be able to pull newsletters and their AI events. With their newsletters, it was their previous email campaigns, but it completely populated inside of Sanity, so you've got both of those in one location, and the beauty of it is there's not a singular curly bracket inside. So when they were actually building this JSON, they didn't even realise they were building JSON in the Studio. It was literally set and forget.
This one, so number four, is a really, really complex one, but it might be useful for certain people out there. This is the idea of, if you look at something like BBC News, you have a document where it may exist on both latest news, and it exists there, and it may also exist on, you know, local news, Nottingham news latest. So those two, it has to exist on at the same time. Now, these are notoriously hard to build, because you have to either build them rigidly, or you have to think of some way to be able to extend these out. And we actually built a custom URL builder to be able to do this. So every single step of that URL, so for example the latest would show the latest blogs of the news, the latest local news would pull all of the latest local news, and so on and so forth, all the way down the URL structure. It's just a really clever way of being able to scale your content completely without a developer, because this is all done on URL route generation, and get all of that rich data put into a hierarchical structure.
We actually built this for Global Cycling Network, and this underpins the entire way that the project works. If you can see at the top there, we have things like the breadcrumbs, where it says GCN, racing, news. Each one of those URLs essentially tells you information about that particular blog post. Every single one, it's stacked up and hierarchical. It's pretty tricky to build, and it's only really achievable because you can do so many incredible things with GROQ and the queries within GROQ, if that makes sense.
And so finally, this one's my personal interest: automating as much marketing as possible. When we're building things for the website, the biggest sticking point that I've always had is generating meta descriptions, generating Open Graph descriptions, thinking about how I'm going to source the imagery for all of these, and being able to populate all of these with, you know, like a keyword-focused, you know, long tail, short tail, all that kind of stuff. I find it incredibly boring, and I think that the easiest way to do it is by generating a lot of this with AI, or basically repurposing content with AI. So with that in mind, I want to show a very quick video, if it works. Yeah, great.
So this is essentially a very quick demo showing how you can generate each part of the title, you know, the description, the SEO, Open Graph. In our case we have something called cards. Cards for us is basically where you would reference that blog post from one part of the website to the next. Essentially, all of this functionality is done using Sanity's AI Assist, and the beauty of Sanity's AI Assist, and this is the real cool thing that I don't think enough people necessarily talk about, is the internationalisation. Right this second, there has never been an easier way to get into internationalisation. Usually, when you are actually publishing something to an internationalised audience, you have to get translators involved. You have a huge, huge, huge cost before you can even start putting stuff out there. Today, you can set up with Sanity, with Next.js for example, and have a fully internationalised website working within a day or two. So there's never been a better time to do it.
And the whole idea of AI, and this is the last thing I want to really talk about, is instead of just generating content with it, because, let's be completely real, if it's just AI-generated content, it's not very good, the main thing you want to do is focus on using it to enrich the content that you would write yourself. So using AI Assist, Sanity's AI Assist, you can basically do a hell of a lot of stuff with the content that you write and repurpose, and save all of that time that would usually get burnt doing these manually. So thanks everybody for listening today. Appreciate you taking the time out, and yeah, cheers.
Thanks Jono, that was terrific. And yeah, I think the AI Assist, it's very tough when you're looking at a blank field and you don't know what to write, but then AI writes something and it immediately evokes the feeling of "I can do something better than that". So Evelina, you're next, if you want to come up and get set up. There are a lot of Sanity people in the room. Raise your hand if you are a Sanity colleague of mine. Look at them all. If you want to bring your questions, bring your complaints, afterwards go and find them, and they will absolutely have all of the answers to all your questions. Evelina is from loveholidays, a longtime Sanity customer, and always very interested to see what they're doing.
Sorry, it's a bit scary. Okay. Hi everyone, welcome. I'll be covering a bit around how we at loveholidays ensured crisis readiness by utilising Sanity to our benefit and having non-developers power the content that builds our app and our website. Just briefly about myself: I'm a software engineer, I've been that for four and a half years now or so, and I did an 11-week boot camp. So I'm kind of an ex molecular biologist turned software engineer. I did a boot camp in Amsterdam, an 11-week boot camp. I'm not going to say I was a great developer after that, but I came to loveholidays and have learned a lot since being there.
And for those of you who don't know loveholidays, it's an online travel agency that's been around for, I guess, more than 10 years now, actually, and the vision is to become Europe's number one holiday provider. We intend to do so by giving our customers a lot of choice and the ability to mix and match their own holidays. Currently we sell holidays in the British, the German, and the Irish markets. In the next slide I'll share a little bit around how we utilise Sanity and our tech stack, just briefly, to set the context, and then I'll go into my own experience in leading this initiative called crisis readiness, and I'll also talk about what crisis means in this case.
So yeah, these are actually just some screenshots that I took of our website. That is the homepage to the left, and then to the right is one of our landing pages, and both of these are driven from Sanity completely. Well, "completely" I say; actually, in the screenshots there's, like, search and stuff like that, but I cut that out. In both content and, like, the static structure of it. We basically empower our non-engineers and non-developers to make improvements to our site as part of a rapid development cycle. You know, maybe you have more certain content driven from Sanity, but we have a lot of content driven from Sanity, and we do this basically in a server-driven UI manner, and I will talk about how that works.
This is not a deep dive at all, but it's just basically to set the context around how all this works. Our website is server-side rendered with client-side interactions and navigations. It basically means that, you know, the HTML you get when you land on a page or land on a URL is complete for that page and shouldn't change until you actually navigate. And then for our kind of JavaScript-served interaction, we use the GraphQL backend for frontend. And then in the past year or so, probably a bit longer, we've been migrating and basically, we've been inspired by Airbnb and how they actually do a server-driven UI. That means that our client, in React and TypeScript, is quite dumb. It doesn't really have a lot of logic in it, and it doesn't really know the concept of bespoke pages. So instead, per a given URL, it will basically request generic page data from the GraphQL backend for frontend. Some of that will come from the Sanity CMS, and then basically our GraphQL server will respond with typed components that the frontend will then render. And yeah, like I said, I won't talk more about this, but I have some colleagues in the audience that have built this and that are experts on this, and also on how we use Sanity in general at our company, so if you're interested in more of that, please come and talk to us later. I also reference the Airbnb blog post at the end of this talk. And yeah, I'm no expert on Sanity, but I just wanted to share a bit about my experience in running this initiative, with the help of, obviously, our dedicated web infrastructure team. I'm looking at Chris, he's the only one that's present here, but we have other people that are great at it. But yeah, with the help of them, and also, I think, just the Sanity documentation is very clear, and I sometimes find tech documentation to be a bit boring, but I found Sanity's to be very, like, entertaining. Maybe that's wrong, but you know what I mean. I found it easy to use, and I think the last time I actually used Sanity was, like, three years ago, because we have more of a dedicated team, but this was quite easy.
So yeah, how do we empower our non-developers to get ready for a potential crisis? Well, basically, I want to start with: what is a crisis in the world of travel? When I say crisis, that can be anything from, you know, wildfires to earthquakes, so anything that can actually impact customers travelling. I will share a real-life example of how this looks, and also in an unexpected way, when one of our accommodation suppliers actually went under, which is not great, but this is basically what we set out to prepare for.
In 2023 alone, there were actually four major incidents, as I'm sure you're aware. You know, there was an Icelandic volcano that erupted, there were wildfires in Rhodes, so there was a lot happening last year, and this was kind of before we had all our server-driven UI in place. And, you know, our customer experience team, they worked really hard to communicate as fast as possible and were able to manage calls and all of that, but we realised there was kind of a clear gap in how we contacted our customers and made sure that that came out quickly. If I look at it from more of a customer point of view: something happens, I'll open the chat, I'll be like, is my holiday impacted, can I still go on my holiday, and, you know, you might feel quite stressed, and there's nothing in kind of, I forgot to say it, but I work in the manage my booking team, so it's kind of, like, the post-booking experience. You'll go to your manage my booking, you go to your app, you'll see something happening, and you don't see anything. Basically, you know, earlier, how this worked is it could take up to three days for this message to get out to our customers, because we had to wait for, you know, app releases and all that. And then you see here in this graph, you can see you've basically missed the influx of customers, and also some people might have already gone on holiday, and we don't want to cause people stress, obviously, when they're going to go on their holidays.
So basically, what we did is that, pre our summer holiday peak, so this was at the beginning of May, we wanted to make sure that we are ready for a potential crisis. Obviously we hope that there are no crises, but as we can see later, this has been used already. And we worked together with a cross-functional team across, you know, customer experience, content, comms, to define what an MVP would look like. And also, it's very important that non-developers and people that are not engineers are part of this, because they're supposed to use it. So from day one we've worked with them and talked about how do you want to use this, and what should it include, and then defined the MVP.
So yeah, like I said, non-developers should manage messaging in this manage my booking homepage, which is this one, I'll talk a bit more in a second. We want to reduce the strain on our customer experience team, and then we don't want to have any app releases for this, because we don't want to rely on anyone else but ourselves to get this out. And we also want to make sure that there are some guardrails in place, obviously, because, you know, we shouldn't just be alerting our customers in case there isn't anything to be alerted about. So that is key. And also, yeah, this is just kind of a snapshot of a holiday. This is in our app. You're going to Portugal, you have your itinerary items, this is the way you can amend your holiday, you can see where you're going, all of that stuff. So the idea is that the alert would pop up here and be part of that. You'll see it in a second. But we don't want to overload that page with too much content, so this was key in defining what we're going to do with this.
So yeah, how did we get there? Obviously with Sanity. And this is kind of the main structure, so you get a little bit of insight into how this looks. We don't have all of it here, because I don't have access to all of it. But you will see here on the left side that I actually created a new MMB directory. It's for several reasons, but one of them is it's easy to manage permissions that way, because obviously not everyone should have access to this, because it's important that we are careful with this message. And also, as we scale, I talked about us wanting to become Europe's number one holiday provider, we need to think of how we scale and have that growth mindset. Previously, we would have maybe put this under, like, site content, but that would have meant that we'd have to copy it from, like, the German site to the UK site, and we're moving away from that, so this was one other opportunity to not use that.
And you'll see a little snapshot of what that looks like. Hopefully everyone can see. Like my colleague said, maybe I should have done light mode and not dark mode, and I realised that before, but I'm a developer, so I do dark mode mostly. But yeah, this is an untitled alert, which is also not ideal, but basically, how it works is that you would add a booking ID. Outside of Sanity, you would run a query, for example, you query the affected bookings, and then you would add that into this simple text field. We did talk about whether we were going to use, like, a file type or something like that, but we didn't really know how to handle that fully, and it wasn't something we had used, so we kind of decided that that simple text field is fine, because we can just add these bookings and filter through them later. We also obviously didn't know, because every crisis is different, how many booking IDs there were going to be. I think we tested around, like, 20,000, and, like, Sanity was fine with that. We were like, cool, this is going to be fine. But I'll talk later about what happened. You live and you learn.
And then, basically, next on this alert we have a headline, and we also have a message. I'll share a bit of how this looks in a second, but both the headline and the message are using field-level localisation, so you can add per language. I've not added anything here now, but you can add that per language. We're also utilising a customised field for the block content here, or the block type, where we're using just a simple paragraph and a link. Like I said earlier, we don't want to have too much content on the page. There's some custom validation around what type of link you can add, there's also some custom validation around how many characters you can add. Again, we don't want to overload. So there's been a lot of customisation going on here, a lot of descriptions to make sure that everyone understands how to use this. And then finally, we also have an optional button, which is also using field-level localisation, and this is if we need to gather more information from a customer, we want to link them out to, for example, a form that they can fill in, so we can contact them with more information.
So yeah, how does this all work in practice? Basically, this is something I kind of quickly put together, but if a crisis happens, the idea is that a non-developer can go to Sanity, add an alert quickly, and publish, and then our GraphQL backend for frontend will add this to something we call a mandatory resource. Basically, what that is, is that we fetch these resources, this data, on startup, and update that data on an interval that we set, and we've set this to 10 minutes. We can switch that, and we can have it be longer or shorter. And basically, it's very beneficial in a crisis like this, because you might need to update your booking IDs quite often, because someone goes on holiday, someone comes back, so you need to be able to get this out immediately. And then the function itself is super simple. It's basically just looping through that data, and then basically going through, doing a GROQ query, and checking, you know, is there an alert? Cool, if there's an alert, we'll do a simple lookup per booking ID and locale, and then decide whether or not to return this alert component. And then, in the server-driven UI way, we can basically server-side render this quickly to our customers, both in app and web. I didn't really speak about this earlier, but we basically write the same code for our app and for our web. We do that with the help of a framework called Capacitor JS, which is basically a framework that wraps a web app into a native app. So we've gone from three days to, like, 10 minutes, basically, if you add this alerting quickly, and it should be simple. I think that's pretty cool.
And then I just wanted to share a bit of how it looked. This is just, actually, this did not happen, this is just so I could share. I added that in, I did this, and then you would see this 10 minutes later, basically, and if I update that booking ID, I would see that in another one. So it works quite seamlessly, I would say. And yeah, we were, I guess, hoping to not have to use this, but we've already used it, like, two weeks later, and we already learned a bunch of things that we probably could have done better. But, you know, that's the typical developer life, right? You always iterate, so I think it's fine.
Yeah, I want to talk about just how we've used it and what I've learned and what we want to do next a bit more. I don't know if people are aware of, you know, loveholidays and have followed, but a bit more than two weeks ago, one of our accommodation suppliers actually filed for insolvency. That caused a lot of distress for our customers, which is not great, and this basically caused us to utilise this alert sooner, and maybe in a way we didn't really think we were going to use it. But that's the beauty of tech, I think: you can always reuse it and change things and use it as needed. So yeah, when the news broke, there was a huge cross-team functional effort to communicate and rebook the people that were actually affected. That was kind of, like, sending out SMSes, being very proactive, so we weren't waiting for people to go to the app and check, we were doing that. But then, as the news broke to a bigger audience, people started kind of confusing that our supplier was us. People thought, you know, we had gone under, so that was not great. And then our communication teams were like, okay, we should probably talk to people and communicate that this is not the case. That happened on social. And then we got an even bigger influx of customers being like, is my booking affected? So there was a lot of, you know, I feel bad for the agents that were working tirelessly to help a lot of customers, and then they get a lot of noise from people that weren't affected, and it's kind of, like, handling that. So we kind of had to think quick on our feet, and what we did is that we changed, so you could see it was kind of a red, critical, urgent alert earlier. I did just, like, a quick one-line change in our backend for frontend, because I didn't really have time to go in and change this in Sanity, and I changed that from, yeah, I didn't say that earlier, but this alert component is something we have that's powered through our design system. We have different variants for it, so it's kind of a component that works for a lot of use cases. So I just changed that from a critical look to an information look, so blue. And we did this, which, you know, it's great that we could use it. The only other thing is that, you know, we weren't really thinking we were going to send this to everyone that's not affected, so that was, like, hundreds of thousands of people, and adding that into Sanity kind of broke the UI a bit, which is fair, because, I mean, we weren't really going to use it like this. That's why you see both of the two alerts here, which are basically the same, but we just split the alerts, or the booking IDs, into two alerts.
But yeah, I think, obviously, it's not great that we had to use this, but it's great that it was in place, and I think we've learned a lot from it. I don't think we could have foreseen that this was going to happen, that we were going to use it in this way. But basically, as of last week, we've already implemented a dropdown, I can share that. No, first, I forgot this, actually. So this is how it would look. People would come in, they were like, you're not affected, you're unaffected, you don't have to do anything, like, don't worry. Also, it's very cost-effective to do this: instead of sending SMSes out to hundreds of thousands of people, we could just get this out in 10 minutes, and we could already see that people were sharing on socials to be like, we're not affected, kind of, I guess, spreading the word for us, and having people go to the app and the website and see that, you know, they're fine, because it was a subset of people, and some of them had already been booked into another hotel. So yeah, again, it wasn't great that we had to use it, but I think it's cool that it was in place, and how we planned to accomplish this in, like, 10 minutes, like, thanks to the whole infrastructure, is pretty cool.
And yeah, what's next? I've already talked about it: I've implemented this dropdown, which is kind of informative, critical. I think there needs to be some guidelines on how and when to use the alert. It shouldn't just be overly used, because, I guess, as I said, they're also kind of pushing the content down, and you don't want to, like, it's supposed to be more of, like, if there's anything the customer needs to do, or if there's something they should worry about. It shouldn't just be used to send out extra information. And then I think it's also, obviously, in a crisis there's a lot of cross-team effort, and it's kind of been some of us engineers that helped out with this. In an ideal world, this should be fully driven by non-developers. They should be able to do all of this, which they can, it's just that they have been working tirelessly on a lot of other things. Obviously, we know this, we built this, so it's not like we can't go in and update this. It's fine, happy to help, obviously. Oh sorry, I went too fast.
And then we have preview and schedule, which we're thinking about. I know our web infrastructure team have worked on this. It's basically, like, a custom field where the preview content would, in an ideal world, basically take a booking from the booking ID list, and log into a staging booking, and then you would get to see it, obviously, before you actually publish it. And then scheduling, I think, is also cool: if you know that something has happened, or you want to send out a new message on Monday morning, you just schedule it. So I think that would be pretty cool to have. And then finally, I think the North Star is that anyone can configure and control messages based on certain booking elements. So instead of having to query that in BigQuery in a different place, you would do all of that, you know, it will be clear from there. You would say these dates, this destination, this airport, and stuff like that. But yeah, this is a bigger conversation, I think, around content models in general, but I think that is something that we thought of. So yeah, thank you.
That was terrific. That was really interesting to see behind the curtain there, and another real-world application that perhaps might be a bit uncommon. I'll get Toby to come forward and start getting set up. I was just thinking through that talk: I create a lot of guides, a lot of tutorials, and I have to create different content models and have to try and think of new ones regularly, and they're usually fun examples, like record collections or holidays or learning or shopping, they're aspirational things. But I don't think I've ever once content modelled a crisis, and that's the reality, that's what's really happening out there. So a new example for the next tutorial, perhaps. But we've got Toby next from Even Six. There are a number of Even Six people in the room here today. I got a sneak peek at this earlier. This really is something. Some fancy visuals on display, and I believe a live demo too. I don't want to spook it, this will be the first one of the evening. No, no jinxing it, it's going to work flawlessly.
So this one might be a little bit controversial. How boring is structured content? Now, you know, this is obviously a bit of a biased room. Talk to a number of people, and they might say very. We're here to challenge that. Okay, we're here to challenge that. Hello, I'm Toby, technical creative director at Even Six. Now, Even Six is a digital brand and product agency, so what that means is, really, I am the creative director at Even Six. It's a single reference, you can see right there. Now, I'm also, as technically a creative director at Even Six, that's an array reference, you can see right there. That's multiple creative directors. Semantics are important at Even Six. Semantics are important for structured content. Semantics are important for Sanity.
The truth is, nobody grows up dreaming of structured content. It's a shame, I know. Equally, nobody grows up dreaming of the W3C, schema.org, page speeds, technical SEO. We grew up dreaming of what's possible. So for me, at least, the web was where that was happening. There were no limits, no restrictions, and infinite possibilities. Whatever you can dream up can be made possible. That was the promise. Have we forgotten that about the web? Sometimes I do wonder that. Like, that was a really exciting moment for all of us, when we used to look at things like Awwwards and stuff like that, and look and think, wow, that's incredible. How did that even happen? How did we do that? Let's get back to that a little bit as well. You know, sometimes I think it's exciting to show what's possible on the web. This is our corner of the web. We can do whatever we want in that place, so let's push it a little bit, is what we say.
So let's show what's possible with structured content. Rather than boring people with the benefits, I'm going to jump into what is actually possible. We believe we can leverage the power of structured content to make digital experiences more current, more relevant, and more personalised, without creating extra work for people. That is the challenge. Can we at least attempt to make structured content vaguely exciting? This could be a stretch. Let's put structured content to work, and then we can all be the judge of that, using a 3D model, because structured content, Sanity, and 3D, you have to listen to and trust Even Six on this one, are best friends.
So let's take a company like Cetti. Now, there are a few Sanity people in this room. I know that Cetti isn't a real company, but just bear with me on this one: an innovative tech-based cycling company. Now, Cetti have products, and those products, they could be a bike, or they could be bike parts. What's familiar between the two of them is the fact that they both use components. Now, we can attach a lot of structured content to those components, which is where a lot of magic can start to happen. So we could say that a component is mentioned in a review, we could say that it's mentioned in an article, we could say that that component resulted in a stat, we could say that it was manufactured by a particular manufacturer, and we could say that component has features. I'll get to the last bit in a second, but what are these components? We could have forks, we could have the levers, we could have the mechanical parts of the bike. Every single part of that bike is a component. And like I was just saying, you could have a review, and that review could be in Sanity. You might be mentioning a certain part of that component that we can see here. We might be just mentioning a particular part of a bike in an article, so somebody might be saying something about the wheels, about the saddle, whatever it might be. That can be quite light. And those result in stats, like I just said, so power increase, things like that. The specs for the bike could be, you know, how much it weighs, it could be the dimensions of it. And there are lots of stories that we can tell here, right? So if we said that this designer created this wheel for this reason, and we wrote a story about that, that can become quite engaging, particularly when you're trying to sell a bike like this, which we'll get to in a second. I think we made up the figure; it was about 10,000, so you've got to tell a few stories to try and convince somebody to spend 10,000. Okay. And yeah, it could be manufactured by a completely different brand to Cetti. It might have these different features.
But what we're here today to talk about is structured content and 3D models. So what does that mean? Well, what we have here, and this is a bit of a, the geeks at Even Six know this is not technically how it works, but we have a component which has a camera position that's attached to the component. We might well have a bike, and that bike will also require a camera position, because the bike has multiple components. Let's zoom out a little bit and show what all those component parts look like together. Now, this is all so far quite hypothetical at the moment, so what we're going to attempt to do, as Simeon mentioned, is a bit of a live demo, to show what this actually looks like in Sanity and in Presentation.
So this is all a 3D model with structured content. You can see that if I start to scroll, it can start to do some quite cool stuff. We can change the colours completely for the page, and if I just go back onto this one, you can then start to see that that component story is actually quite powerful, because now what we're looking at is the cockpit of this bike, and that is pulling some content. Now, if I go into this page just really quickly, you will see that this cockpit, this component, has literally no information in it. So why is it that there's no information here, but I'm seeing "a seamless single unit construction", all the description about that component? I can see what material it's made from, the weight of it, I can see the designer, the brand, and even a story that's related to it. Well, that is the power of structured content at work. One of the things that we can see from over here is: this is the article that references that piece of content. If I was to go into here, I can show you that somebody's done a product callout. So somebody might have merchandised this article to reference a particular product. Now, as I showed you a second ago, a product could be a bike part, which is still a component, so we can resolve all of those references, and that is how that piece of content made its way into that page, literally just by somebody merchandising an article. That's the power of structured content at work.
Okay, so now we're going to attempt some of the more dangerous parts of our live demo. Just to prove to you that this is a 3D model with all of these component parts within there, I'm going to now attempt to reorder this 3D model, and this is something that can be created so content editors could tell a more compelling story on this landing page. So what we're going to do, everybody bear with me on this one, is we're going to put the fork to the top of the page. We'll give that a second. This is the power of using Sanity and Presentation. You can start to see all of this structured content coming together and even be able to navigate it. That's what Presentation is there for. In my opinion, you can do some very complicated things. Now, hopefully that has updated. No? Yeah, it has, yeah. Cool. So yeah, so now you can see that the fork's at the top of the list. I can just reorder it, and that is because the camera position was put against the component. We're not trying to, you know, create 3D models all the time. We're trying to work smart here. So camera position, everything, is all bound to the component rather than to the bike itself.
Let's go a step further and try and do something even more complicated here, and really push it. Okay, so here we have the S600 cockpit, seamless single unit construction. Let's go a little bit of a step further, and let's see what happens. Let's pretend that Cetti just brought out an upgraded version of that cockpit, and that is an array list. This is set up so it can actually play quite nicely as a product configurator. Here we have the S600 cockpit V2, and I'm going to publish that. It's really, really tested now. Okay, so just look at that. There's nothing on the top of that cockpit. I feel like a magician right here. Here we go. So does everybody have their fingers crossed? So here we go. Now you'll notice that product can just be updated. It's a component part, so you can update that from a single place. That bike has multiple components. I can update a component part of that bike, and everywhere that I show imagery or 3D for that bike can be updated from a single source of truth. That is my attempt to try to make structured content exciting for everybody. It was a short talk, but hopefully you all enjoyed it. Yeah, that is the end of my talk. Thanks.
I think that absolutely succeeded. The flash is back. Oh, now I have to get set up. So what you saw there is also our demo that Even Six helped us out with, that's great. Maybe at some point you can buy those bikes. If the content management stuff doesn't work out, we can pivot to bikes. Let's see. Yeah, there you are. All right.
So we have been doing stuff the last six months or so, and what we very often notice when we go on about it is that people didn't read our email about the new thing. They weren't aware that we did the thing. And to catch you all up, and amend for that, we have, I think we have 96 slides, so I hope you didn't have to catch any flights. Yeah, we'll let you know what we have been working on, and some future stuff, some stuff even available in the future, and a thing we shipped today while we were here. So yeah, give me 10 seconds. All right, excellent. Yes, I talk quickly, so we can get through 96 slides very quickly.
All right, so today's talk is called Sanity is cooking. Who's used Sanity for at least a year? Keep your hand up. Three years? I've been at Sanity for three. Got some for five? I started five years ago, 2019. Looks like everyone tapped out. All right. So I've had the pleasure of being at Sanity for the last stretch. Now we have this locales repo, which is really clever. Some of our engineers hooked that up with AI, so there are AI-powered translations of new strings as they're added to the Studio, and you can also localise your plugins as well, so anything that you ship. Let me present, share screen. I don't need to narrate this, but I will: share, click, wallpaper, alt tab. Excellent, we're back.
The validate documents CLI. You can now validate a dataset. Previously this was a very difficult thing to do across all documents; you had to validate documents one by one, and that can be quite slow and annoying, but now you can just run this command across the entire dataset. Is that a video that's going to run? No, but you can run that from the command line, and it will show you the status of all of your documents there. And this was an important step to get us towards TypeScript support, I believe, the ability to just check all documents in the dataset. Because even though you write those validation rules in the studio, the data stored in the Content Lake is not guaranteed to be one-to-one with what your studio says. So the studio can be a lie, and the Content Lake will send you anything, because you can write anything you want to the Content Lake. So it is important to be able to validate documents against your studio markup, and it will tell you, oh, the video is playing, it will tell you what's valid and what's not, what you need to go back and fix. This is also excellent for migration, because the content that you pull out of some other service is likely broken in some way, and so to be able to migrate thousands of documents into the Sanity Studio, into the Content Lake, and then validate the status of them, is very important as well. Thanks, YouTube.
Comments are now on by default, in the January 19 release. So comments, one of those things that, I'm really excited about comments in the Sanity Studio because of how boring they are, in such a way, like, they just work. There's not really much to them, but they have been a huge unlock of productivity in the studio. Just one of those features that, once we shipped it, you just assume they've always been there, because it was so useful to use.
The desk was renamed structure. You might see that deprecation in some of your imports as well. Small thing, but we did also ship a codemod to go and rename that in your code, so if you don't want to change two lines in your studio, we can do it for you. And we also added a union cache to GraphQL deploy. Who knew that? I didn't know that, and now I do, and it apparently improves schema generation up to 95%. Again, these are the things you just miss out on if you don't trawl the changelog every week.
We got deprecated fields. Now, I'm not sure if anybody's used this, but this has been really useful when you've got a really long-lived project. If you have been using Sanity for five years or so, you've probably got all sorts of hairy data that you need to get rid of and get editors to stop using. You can mark it as deprecated. It has no functional effect on the data, but it at least gives a nice big scary warning to somebody, and you can tell them not to use this field anymore and to use something else. You can deprecate document types, you can deprecate singular fields.
We also shipped comment reactions, because those are extremely important for boosting morale, and sort of giving that thumbs up. To me, the thumbs up emoji has a double meaning now. It's like, please stop talking, this conversation has ended. That's what the thumbs up emoji means to me.
The all-new Sanity Studio design. This one could be a bit spicy, actually. If we wanted to put an emoji reaction on this one, maybe a hot pepper would be good, because it completely changed the design of it. I won't ask for a raise of hands, who loves it, who doesn't, but I think, now that it's settled for quite a while, it's great. Redesigns of applications are very difficult. The team put an awful lot of work in to clean up the studio, and it does look cleaner, and I know certainly it's grown on me. It's reduced the visual noise that was there before. Everything kind of looks very big in some of the old studio screenshots you'll see here as well.
There's some migration tooling that we've launched as well. This has been really awesome. They are migration tooling helpers, so that you can create migration scripts. Previously, if you needed to migrate content inside of a Sanity Studio, and this is more thoughts around long-lived projects, where you need to change data structures, if you've ever had to change a single reference to an array of references, if you've needed to change a string to a portable text field, those can be quite tricky things to do. So now we have these migration helpers to create these scripts for you. They will do the more difficult things, like batching transactions together. They also have a sort of secondary usage, and again, it's where my mind's at at the moment, which is actually using them for migration tooling as well, because they do handle bulking together transactions. They can be very useful for creating new documents at scale as well.
I'm not sure why that slide's there. No, schema validation, that's different, isn't it? We were looking at document validation before, so now we're going to do schema validation at the same time, to check if there are any issues in the schema. I think this was also a stepping stone towards our TypeScript support. Usually when I do these meetups, I'm one of, like, two people from Sanity in the room, and now that there are more of you here, I've got this pressure on me that maybe some of the things I'm saying aren't true, and when there are no engineers in the room I can just say that stuff and you believe me, and now there are engineers in the room, I'm a little bit worried. It's useful for migrations as well, schema validation, so that's excellent. All right, great.
AI Assist version two launched, which actually was mentioned in one of the talks tonight as well: the ability to translate documents. There was a lot of work put in to make sure that the AI Assist was configured to work with all of the different ways that you can localise content. We do realise that there are a number of ways: you can do document level, you can do field level with objects, field level with arrays. The translation with AI works with all of those, it is designed to work with all of those, which is excellent. And it's very much designed to just be the fastest path to be able to translate documents and translate content and have it write straight to the studio. If you need more options, other providers are still useful for that, and that's why there's still support for those, but if you just need the fastest possible translations in the studio, you click that button and it will do that straight away.
We launched comments in the portable text editor as well, in March here. So now you can actually select short snippets of text and be able to write comments directly on individual pieces of text inside portable text. That wasn't shipped with the first version of comments, but it is there now.
There's the ability to weight searches against particular fields, and there was an update to document actions too. So when you are writing Sanity schema types now, you can infer that some fields have a higher weight than others when you are searching in the studio for those things. So perhaps when a person's searching for documents of a particular type, you want to make sure the name field carries more weight than the description, for example. That's one. And now this next section, this is the one that I am certain nobody knew existed, outside of the engineer that made it, for the person that they made it for: your document actions can actually appear out here now. Why? I don't know, but when you write a custom document action, if you want it to be in the top pane there, it can. So that's really great. You couldn't do that before, and now you can, and we're really just ticking off all of the most hotly requested features, so I'm very, very excited to show that one off tonight.
Persisted user settings, a change that you might not have even noticed, but just an absolute quality of life upgrade for editors. That is, when you have desk lists, desk lists like these, and you're able to sort them and set these settings, these settings are actually saved server-side now, so that if you refresh the browser, you log in from a different computer, those settings will actually be retained. Where it used to be, I think, that was written to local storage, so perhaps only that browser would save those settings; now those are saved to our servers, and that opens up the gateway for us to save a lot more per author, and make sure the studio is much more configured to that person.
TypeGen. This is probably one of the biggest headline features launched in the last few months, and definitely among the most popular feature requests, this one. This GitHub issue going back to 2020. There have been a lot of community efforts around this, and efforts even by our own engineers, and so there's been some amount of tooling out there for quite a while, but we needed to have something. So we sort of looked at those as early work, and certainly our work builds on the shoulders of those, but the solution had to be twofold for us to be really happy with it, and that was: one, to be able to generate types from schema, and types from queries. Because, again, the content that comes from the Content Lake can be different to the content in your Sanity Studio, because maybe your GROQ query reshapes the content. So to be able to generate types from schema was to be able to extract the schema down to a JSON representation, and then be able to generate TypeScript types off of that schema. So now, when you are creating schema like you always have, you extract that out to a JSON file, which then you can generate these types off of. This really solves one side of the equation, which was really, really useful, to have types based on your schema.
But the part that I know personally I was really excited about was the types from GROQ queries, because this is really the power of the platform, and that was brought up in one of the talks tonight as well. It's one thing to be able to structure content in one way in the studio when you're authoring it; to be able to reshape that into whatever application is going to consume that content, that's the real power of GROQ. And so that we can generate types from GROQ queries that just do anything with your content is really excellent as well. You do need to make sure that you're prefixing your GROQ queries with the groq template literal, like is being shown at the top there, and it will generate these types with the typegen generate. It does mean that you do need to keep running that generation script every time you change your schema or change your queries, but at least you do get up-to-date types. And with that configuration down the bottom there, it does mean that if you've got your studio and your front end in different repositories, different folders, sorry, it means that you can sort of read from one source and export to another. So really excited to land that one, and I know that was hotly requested, and a huge quality of life upgrade for developers.
Tasks shipped in April. This was in beta, I believe, but sort of a fast follow-up to comments was the ability to assign tasks to people. This has both the benefit of having authors work together in the studio, not having to work outside in some other application and then bring their work into the studio, but also it can block publishing, so a task needs to be complete in order for something to be published. So it's just really great to bring that stuff into the studio, instead of having to do your project management over here and your content editing over there. You can do it all in the one place.
We launched enhanced search on April 16, which actually was disabled shortly after, but it probably will come back. It's going to be a server-side search of your Sanity content that ought to be much more powerful than just the client-side search, so something perhaps to look forward to in the future.
We have presence cursors in portable text, which also came out. So you've got multiple authors. Sanity's always been multiplayer. I know multiplayer is the new hotness, but Sanity's kind of just always been like that. But now we have this in the portable text editor as well, so you can see cursors inside of portable text and see which author is where in the document. Comments and tasks came out of beta as well in that release, so they're considered stable.
Scheduled publishing is now part of the core Studio package. This used to be a plugin, but we consider it valuable enough that it sort of needs to be inside of every studio, so you'll always see this.
You can now save query results from Vision out to CSV files and JSON. This was brought up by one of our engineers in a recent online meetup that we had. You've got these little save buttons down here on the right-hand side, so you can export those queries out really quickly, which is excellent.
Another one of those things you might not have missed and may never need, but if you have a custom component inside the Structure Builder, it can now handle intent links, which, if you've ever needed that, that's so thrilling, and if you haven't, then terrific, keep living your best life. But yeah, you can drop any custom component, so that's a Structure Builder thing: you don't have to show our document editor there, you can just drop in any React component you'd like, but this now allows you to make sure a link from somewhere else in the studio will respect and find that component. So that is actually really, really cool.
We now sync back to Shopify metaobjects. The Sanity Shopify Connect application has been around for a while, but we continue to work on that as well. It's probably the simplest integration we have from Sanity to something, to be able to get product data from Shopify into Sanity, but now we're writing content back as well, into metaobjects. Some people want all that content in Sanity, some people want all that Sanity content in Shopify. We are doing much better to support both use cases now, and that Connect app keeps getting better and better.
The Actions API launched only recently as well. It's a high-level alternative, it sits on the Mutations API. A lot of what the studio does in document actions, so create, duplicate, creating a new draft when you start typing in a published document, a lot of that was just studio client-side logic. The Content Lake didn't actually know what it meant to create a draft for a published document; that was something that just happened in the studio. Now all of that happens server-side. Probably the biggest pain point, I know personally, for me: if you've ever used Sanity Client to patch documents, and you've wanted that logic of "I want to patch the draft if it exists, otherwise create a new draft from the published version", that's usually required a lot of logic that you've had to do yourself. You have to query the document first, find out if there's a draft; if there's not, you have to create one from the published document, set your revision, and do all of that. But now we have actions to be able to do that and much more. So everything you saw in document actions, a lot of the logic that you saw in the studio, that's all now done server-side. This opens the gateway to build even more complex applications outside of the studio that do studio-like things with your content.
So that's a really quick recap of most of the big feature releases in the last six months. Some of the things that you've seen there, though, require the Growth plan, so the comments and tasks. But if you ever need to try that, you can spin up a brand new project immediately, and you do get this upgrade to be able to try out all those features. So if you are trying to put this in front of somebody, this has been a difficult thing in the past; you're sort of just describing to them some of our marketing points, but now you can actually show these things, because a brand new account will get a 30-day trial of all of those features. So you will actually get to try tasks and comments and all of the best features when you start a new project, and spinning up a new project is free and instant from the command line, so spin up as many projects as you like to try those things out.
Sanity Learn is also something new that got launched as well, and this is where I've been spending my time recently. I know I've spoken to some of you already about the learning platform. This is a Remix application that we've got running now in production. It is where you can go and have your hand held through the journey, start to finish, of, say, setting up a new front end, trying out the schema migration tools, trying out TypeScript, learning more about structured content, putting a team together. There are sort of some conceptual, project manager style things in there, there are some very developer-oriented things there. And it's also the path towards developer certification, which will be launched for all developers later this year, but we're working with agency partners first to get certifications done. The certification exam is complete, and we will be in touch soon with a few people to reach out to first, but we're going to want to start seeing some Sanity certified developer badges on your LinkedIn profiles very soon.
Sanity Create also launched quite recently. This is a whole new app; this is our first other app that we've launched, and it's a distraction-free writing environment that is made better with AI. This is an example of some of the things that you can do, and as you can see, it's a much cleaner experience. It is built on Studio technology, but it is not the Sanity Studio. Anybody can just start a new Create project inside of the application, so you get those sorts of usual text editing features that you'd expect, sort of much cleaner than writing in the studio, but we also get this ghost writer thing off to the side here. We've got more of the text formatting features being shown here, but you can see the little icon off to the side. It happens in this, or maybe the next one. Is there not a video of the AI actually working in this? Who cares about AI? Okay. It is really quite amazing, let's just go back here. The big difference is you can set up these notes that allow you to set context for the writing that you're authoring. So beyond using all of Anthropic's models and understanding, you can give it your own context, your own understanding, what's important to you, and then it will help you finish sentences, it will help you write things out. I mean, the Sanity developer certification process was assisted with AI there, to help sort of write out what was that going to look like, what was a programme going to look like, and it does really ease the editing process, and you still write something that's very unique to what you are trying to do.
The next set of slides are really important things that are now true, particularly for people who've used Sanity for quite some time. It sometimes surprises me, having conversations with people who have used Sanity for a while: perhaps you tried something once, and that's how it worked, and that's how it's always going to be. And I know I'm like that: you try a new software tool, and if it didn't work right the first time, you sort of walk away, and years later still believe that that's how it is. But I just wanted to debunk some myths about the things that are no longer true, and things that are now true.
Visual editing is available on all plans. When it launched, it was Enterprise only, and when it launched, it was only on Vercel, Enterprise only. And so Vercel still have some documentation here, but you can do visual editing on anything that you like. The "only on Vercel" bit is that they will add overlays to your preview builds and you get sort of their editing widget thing, but really, this editing experience here, you can do that on any front end, and you can deploy that anywhere. And if you've got, like, a dynamic server-rendered app, you can put it into an editing mode just like this, and have that click-to-edit, which is really excellent.
Visual editing is simpler to set up. This has been an ongoing effort by our developer team, certainly with our educational efforts, to try and make clear how much simpler this is. It did used to require many different things all to be set up in a row. You do only have to set up the server-side loader, and you can put something in your front end to sort of do the refreshing for you. If you want it faster and better, you can also add this client-side loader, and it will give sort of sub-second updates inside of the Presentation tool. But yes, there are fewer dependencies, fewer requirements to get that started, but we still have really fast, really excellent live preview if you want it.
Presentation is now the best place for live preview, and my heart sank a bit earlier when I saw that Youssef had the iframe pane. This is how previews have always been shown, and I'm not saying you can't do that anymore, and the iframe pane is still fine, so I really should have deleted this next slide. Sorry, it's having a nap, like Remix. Again, yes, so I mean, it's not entirely dead, but it is better to put it into Presentation, and we still have built a bridge between documents being edited and the Presentation tool. So when you use that locations API, you get links at the top of your document there that will take you to the Presentation tool, and then you have this icon at the top right here that will take you back to the document. So even though you are hopping out of that document editing flow, you still can navigate between those two documents. So yes, while the iframe pane still does work, and sadly, I should have retired on the iframe pane. I think it's my most popular npm package of all time, it is literally shipping an iframe out of a React component that took a URL as a prop, but I think it's my greatest contribution to open source, as it still is, and now we've killed it, so thanks.
You don't need to filter drafts out of queries. Again, if you've been using Sanity for a while, you probably wrote queries like this. If you had an authentication token in your client, then it would return draft documents, and you had to add that to your query. You don't have to do that anymore since we've launched perspectives. Perspectives will filter drafts in or out of your queries as well. So you can protect your draft documents with a published perspective, but you can also make sure that drafts overlay your published documents when you want to, with this perspective, and that's set on the client. So just a few things that are no longer true.
The Live Content API. This is something we've shipped recently, and this is among the more exciting things I've seen us ship recently. And I feel like, if you think you've got feature requests at Sanity, you should see our internal Slack. I think I've got you all covered. And this is yet something that I don't think I ever really thought that I wanted. We've had live preview for draft content, and we've had listeners to be able to sort of listen with the API to changes as they come in, but what the Live Content API does is it gives you a way to add a small amount of client-side JavaScript and listen on the query. And what this allows you to do is actually pull live, up-to-date content, not from the API but from the CDN. So your client-side application can be made aware there has been a change made to this published document, because it's tracking the query and the params that you're using, and when those changes occur, it sends you some tags. You just send a request back to the server and say, run that query again from the CDN, but use this tag, and it will give you live, up-to-date content. And so this is far better than the previewing content, the draft content preview, because that requires authentication. It's far better than the listeners, because that hits the API. This is live, almost real-time updates from the CDN, and it's entirely secure; it doesn't require authentication. And so it's actually used on the Sanity Learn app: if you complete a task in one browser, it will update another browser, even though the query for your progress is a private query being run server-side, because the client can be made aware this query and parameters has been updated. There's a demo here. This is in a Next.js application, but again, this can work in anything, but this is the experience that you weren't able to do easily before. You sort of had to hit the API to get this fresh data, or you would have to sort of wait a few seconds for the CDN to update. Now you can do things like a live blog, or sport scores, or anything like that. Hit publish, and now the website is updated with that content, and, again, for the fifth time, it's coming from the CDN, not the API, and I think that's really cool. It unlocks a whole new bunch of possibilities where perhaps you'd use Firebase or something like that to do that instead, and you'd have to have your data somewhere else. Now you can do that from right inside of Sanity.
Don't tell anyone, especially those listening on the internet. We're streaming this online and telling anybody not to share it, but hey, this is what we're also working on. A lot of people have made their own custom blocks for the selector of the array items. I think this might have shipped today. This shipped today, so this is not under construction, this is out there. So the add item dropdown is now searchable, it has tabs, it has custom preview components. We know you love building page builders, so let's just lean into it.
Another hugely requested feature: the ability to copy and paste blocks between documents as well. This is one of those things that I think every Sanity engineer has a proof of concept laying around on a branch somewhere, and it's just never gotten together to ship it into the product. Well, we're going to ship that into the product, most likely sometime soon.
Another pet project that I think we've all got a version of, and certainly, I did a demo of this three years ago, which partly got me my job at Sanity, was a bulk editing view. I think bulk editing views are known as the widowmaker internally, because everybody's had a go, and then you just reach that spot where it's just too difficult. But this is actually under active development, which is really, really exciting as well: to be able to make bulk edits, and be able to see things in a table view.
And we have one more, on the array selector. What even is this one? Oh yeah, this is that nested item view. So instead of having to drill down through modals, which, you modal, modal, modal, modal, modal, and have to click all the way down, what if you could just navigate your entire array of objects in a tree view like this? This is going to make getting through those complex arrays of objects and page builders much simpler to do as well. So that is also under active development with our design and engineering teams.
And one more thing that isn't visually very interesting, but is just a command here: sanity build auto-updates. So what about shipping a studio that pulls in its own updates and keeps itself up to date? Because we are shipping, we are cooking at the moment, so a studio that doesn't require you to redeploy and run npm upgrade, that would be a great benefit as well. So auto-updating studios: under active development.
The next one might need some discerning. We've got some GROQ here, but it is the top line of the GROQ that we need to pay attention to. You've always been able to run functions in your queries, but you've not been able to define functions before. So this sort of brings a whole new level of complexity to your GROQ queries, and options that you've not had before. You don't have to wait for us to ship new functions if you just want to write your own. So user-defined functions in GROQ queries is also being actively worked on as well. Just don't tell anyone you heard it from us. Is it useful? Why is it useful? Are you asking me? You have already made an answer for this. I have an answer. Can you tell me why it's useful? I could make up something, but then I'd fall on my face. Yeah, that's true. So the initial draft of this just looked like fragments, like you might be used to with GraphQL, but at some point we realised that actually being able to write your own functions to do what you like inside of that, instead of just writing small individual queries and then sprinkling those queries through, that you could do something much more dynamic. And so this allows you to resolve a block any way that you want, and sort of run much more logic in there as well. It's a very simplified example, but you might be able to already imagine the more complex handling you could do of things, say, accepting if the type is this, then resolve it like that. I know those things are very useful for things like resolving links, resolving internal links, to be able to give a different slug structure based on the type of the reference. So yeah, all sorts of use cases for that once that ships, and very exciting to see as well. And that is slide 94, that's slide 95, we're done.
And that's it for proceedings. So I'm not sure if Knut, if you had any more closing comments, but thanks again to our lovely hosts for tonight, this has been excellent, and thanks everybody for turning up as well. A massive turnout, and yeah, really cool to see everybody. Come and ask us questions afterwards. I'll hand over to Knut to finish.
I am amazed that, like, it's two minutes left, so, like, we ran fine. Yeah, again, thanks to everyone who came, thanks to everyone who watched the stream, thanks to Alexander and I that came from Norway to be here to represent, thanks, and thank you very much to the speakers. We have some swag for you somewhere. There's some Sanity swag around, some coasters, some GROQ, yes, maybe some GROQ rocks socks or something left, stickers. Make sure to grab some; we don't want to take swag home, basically. There's still sushi and drinks. I don't know, like, when will they kick us out, you can, like, do a Berlin style party until the early hours, whatever. Okay, awesome. But yeah, feel free to stick around, talk to the speakers, interrogate them about how they did things, talk to us, and have a good time.