Achievements Unlocked!

Yiannis H

Yiannis H

Aug 01, 2024

Achievements Unlocked!

Why I love on-boarding achievements: they show new users around and help them use the app to its full extend - they also remind me of my childhood.

We are trying out many ideas to increase one of our important KPIs - help users create portfolios without a lot of hand holding - and the only thing that seems to work is achievements.

We looked many implementations but we wanted something that:

  1. Was VERY light and fast (one of our rules is that everything needs to be extremely fast)
  2. We can customized it to our needs without spending weeks in development

If you want to read all the nasty tech details, keep reading. Else, you can create an account (it's free!)

How we did it

My objectives when thinking about the implementation:

  • Achievements should be non-intrusive. We have different kinds of achievements that check different kinds of stuff - I wanted them to be as less intrusive as possible in code (i.e. no need for functions to be rewritten in order to accommodate achievements).
  • Separation of concern. Any other developer working on the codebase should be able to modify, delete or add code to the codebase without the need to fully understand the achievements.
  • Cost of checking for the completion of an achievement should be minimal - polling changes and/or checks in set or random time intervals were out of the question.

Here's a simple diagram of my approach:

Now in order to add a new achievement all you need to do is to add an Achievement object to achievements and call updateAchievementState(<new_achievement_index>) when the achievement is complete.

Here are a few examples:

  • External addition

Achievement: "Create a portfolio"

<div>
<button
@onclick="createPortfolio(); updateAchievementState(1);"
>
Create Portfolio
</button>
</div>

This is a less risky approach that allows anyone to modify (or even delete) the createPortfolio function without the need to know how the achievement system works. However, problems arise when we have more complex logic.

  • Internal addition

Achievement: "Make a portfolio public"

function setPortfolioPublic(val) {
// ... function code
if (val) {
// ...
// creating a new portfolio is achievement level 1
updateAchievementState(2);
} else {
// ...
}
}

This approach allows for more complex logic for our achievements. In this case making a portfolio public means clicking a switch, if we just used the previous approach we would be calling updateAchievementState even when the switched is turned off.

What's next

We are thinking to include credits for users that go through all the achievements. That means, the more you explore the product, the more you win :D

What do you think?