In the world of web apps and mobile apps, there is a lot of planning, designing, and decision-making even mid-development. When you already have a complex system in place, new features can really break the app’s UX; or your code; or the app’s performance.
Let’s consider this example:
We need to implement a “favorite” feature on our posts. After saving a post as “favorite”, three other actions need to be made - triggering an email, a push notification, and updating the recommendation algorithm.
A “favorite” feature seems as easy to implement as it gets. But consider that the logic behind adding something to favorites can not only take a long time but also break after the user has already waited for the response. This is the point where we need to make a decision and it is as much a UX decision as it is an implementation one.
Many other scenarios can make you face the same decision. Things like having multiple microservices and the favorite action traversing quite a bit, or having an email trigger when someone favorites your post, etc.
To go a little bit deeper into this topic and have something visual to help you better understand the concept, I have also prepared a video here.
The app
Our app is very simple, but also very important to our customers (currently just me): it is a feed of meme templates. I was lucky enough to find Imgflip’s API and started coding a simple feed that fetches a number of meme templates, shows the title, image and also adds a favorite button for each post. At Wolfpack Digital, we mostly use Vue or Nuxt (here’s why), so I went with the same stack.
The like/favorite button was set up like a booby trap, as I always made the user wait for 3.5s, and after that, the action had a 50-50 chance to fail. This way, we were able to reproduce both successful and error behavior and see how our app would react in both these cases.
The natural first thought - that doesn’t really work
My first thought when implementing actions that might take a while (I think working with mobile apps has definitely influenced this a lot) is to add a loader and only update the UI when the action is successfully completed. If the action is quick, that is great, but what if the action is taking a long time? I will need to start thinking about blocking the user from pressing the same button again while it’s loading, also only “loading” a specific component/item, so the user’s UI does not get fully blocked from such a minor action.
Also, a significant issue would be error handling. The user hits the like button on a post, sees the loader, but decides to continue scrolling. After 2 seconds of only scrolling (or even worse, liking 10 other posts), an error message shows that the action failed. That would be confusing and frustrating.
Optimistic rendering - I got 99 problems but stopping the user ain’t one
Optimistic updates (a.k.a. Optimistic UI) is a pattern that we can especially see in frontend/UX development where different actions update instantly on the visual interface without waiting for confirmation from the server.
Github is one of the many companies that do this - I have seen similar examples from Twitter, Facebook, Instagram. When I hit the star icon, the UI automatically updates and the API call starts. But the UI is already changed as confirmed long before the response comes back as successful.
So let’s update our code! And actually, everything is pretty simple: instead of handling the UI update inside the .then after the await method that does the API call/action, we just update it before even calling. The only thing left to do now is error handling & updating the UI back if the action failed.
The result makes a lot more sense from a UX standpoint.
Error handling
You have spent the last few minutes reading about how we manipulate the UI and pre-fill everything assuming it would magically work. But we still need to set up some code to know if something failed.
The video below covers what I would consider as bad UX, but might be the best example of this pattern’s weakness: visually representing a failed action. The user usually moves on, scrolls further, and showing an error will just make everyone wonder which action actually failed and why they are getting out of their flow for something that happened a few seconds ago.
This does not mean that we shouldn’t handle errors, but we need to choose our behavior very carefully:
we could just log the error and never show the user visual updates in case of failure
another option would be a great error message (so we would know what action actually failed), but that is also very unobtrusive
giving the option to retry, like adding a small button for the certain area that failed
as soon as we find out that a call failed, update the UI back to the correct state; make sure no heart icon is left behind
silent retries are also an option, but there should be a limit
Important decision making
This pattern is not great in all situations. It replaces a bad user experience interaction - taking too long for interaction - with something that may be even worse, but happens a lot less. That’s why we need to choose wisely and be careful before going for it.
Of course, there are some good observations that we can take into consideration while going through the decision process:
avoid applying it for destructive/constructive actions - interactions that delete, create or edit an entry, especially if at the end of a long flow
this pattern works great with boolean actions - marking/removing something as favorite or liking/unliking
it is very important to apply this to reliable actions/API calls. For a small, binary action, but with a success rate of only 50%, this is definitely not a great option
the same applies if the API is always slow and takes a very long time to complete; we are trying to be optimistic, but it is not a great idea to let the user just move on and start a lot of actions, all with a successful UI update, before the previously called actions are confirmed as completed
sometimes a delay is expected (for example a change in permissions) and it is actually preferred to wait for confirmation before moving on
Conclusion
This pattern needs a very high level of communication with the design team, as it affects the UX of the whole app. The basic concept assumes a highly reliable and (hopefully) binary action will complete, updating the UI accordingly before the actual confirmation arrives.
Very similar optimistic patterns can be seen in multiplayer games or in concurrency (where multiple locks are managed with the calculated hope that they won’t interfere with each other).
I hope this article will help you make better decisions in the future. Also, if you’d like to keep learning, I suggest you check out this guide to understanding business logic as a QA specialist. You’ll find plenty of good tips on decision-making there as well!
insights
pack knowledge
Designing Healthcare Software with Privacy-by-Design
Cristian Virciu
Head of Product Design
Reading time: 9 min
Mar 26, 2026
Privacy-by-design is a framework where data protection is embedded into product development from the very beginning. Instead of building features first and then layering on privacy controls later, you design systems that minimize data exposure, enforce access controls, and provide transparency by default. It’s a product strategy decision as much as a technical one.
How AI helps you launch an MVP faster
Gina Lupu Florian
Founder & co-CEO
Reading time: 4 min
Mar 23, 2026
AI can cut the time it takes to build and launch an MVP by compressing every stage of the process, from analysis and prototyping to development, testing, and internal coordination. However, this only works if you use AI with discipline and a clear product strategy. Moving quickly without a plan just leads to scattered effort and higher costs.
How Much Does Web Development Cost? A Complete Guide
Oana
Marketing Specialist
Reading time: 12 min
Feb 26, 2025
Building a website is more than just designing pages, it’s about creating a functional, high-performing, and scalable digital presence that meets your business goals. Whether you're launching a simple business website, an e-commerce store, or a custom web platform, the cost and approach will vary based on complexity, functionality, and long-term needs.