All posts

How are we building userled?

min read


Userled is built using a continually reinforced deep learning algorithm hosted on the blockchain…

Just kidding! Although that might not be true, Userled does pose a lot of challenging problems spanned across a wide variety of areas.

What we do

This article serves as a sneak peek into how we’ve built Userled. We take great pride in our solutions and hope you enjoy going through them with us.

Userled’s architecture can be split into 3 main pillars. Namely:

  • Backend - 🧠
  • Frontend Web App - 🧑‍🎨
  • Client SDK - 🤖


We love Golang. It’s simple, fast and industry proven. It also helps that all of us are hard believers in strongly-typed languages. They help us catch our mistakes (yes, even we make mistakes) early on within our editors and at compile time.

Sadly, language choice alone won’t lead us to victory. We need to scale, big time! Handling tens of millions of events daily is not easy. To help with this, we are building our backend in a microserviced fashion. Think Kubernetes for orchestration and gRPC / Kafka for inter-service communication. Simply put, it gives us the extra horsepower for the parts that need it, whilst ensuring everything keeps running 24/7.

We persist data in our beloved PostgreSQL Aurora and make use of Redis in our crucial paths. We deeply love this combination. Not only is it fast, but it provides an excellent development experience.

Frontend Web App

The frontend world can be a scary place for the uninitiated. New web technologies are popping up left and right on a daily basis. At Userled we keep it simple. Our weapon of choice is Typescript React accompanied by NextJS for that extra flavour.

The reality is that no matter how good our backend is, most of the impressions stem from the Frontend. And first impressions last! We aim for a lightning-fast, silky smooth and simple-to-use web app.  We make use of libraries such as reactflow for Journeys and Chart.js for analytics.

Client SDK

Our SDK is the key to displaying prompts on our customers’ websites. It can be split up into two parts:

  • Loader - this is a tiny JS script. As a Userled customer, you need to insert this one-liner onto your website to “install” our services. This script has one job and one job only: install the SDK Core.
  • Core - once the SDK is installed, we’re live! The SDK establishes a connection with our backend, allows our customers to invoke methods, and enables us to render our all-important Prompts.

Here’s the tricky part. The SDK lives on our customers’ websites and executes on their customers (our customers’ customers), meaning it will run on A TON of browsers!

It’s key for the SDK to be:

  • Small - a small bundle means less data transmitted over the wire and less code for the browser to execute. Speed is of the essence.
  • Secure - although we are not processing any sensitive data, we need to be careful not to introduce a backdoor to our customer’s websites.
  • Compatible - the SDK should be able to run on all browsers.

Introducing dependencies increases the overall bundle size and potential vulnerabilities. We keep the logic low level and optimise for speed. Hence, our solution here is barebones: raw Typescript! Compiled down to good old JS using Vite 🤝.

Prompt components

You might be thinking to yourself: “Wait, I thought there were only 3 pillars to our build”. Well… we lied. There’s a fourth and it’s our secret sauce!

Let me explain. Userled customers can create, customise and save prompts on our website. These prompts are, later on, displayed on their website. Because of this customisation, we need to be flexible and support a variety of options. A prompt can be red or maybe white. It can have an image, hell, it can even have a button!

Here’s the tricky question: What is a prompt? To answer that, we first need to look at the following questions:

  • How can we render prompts on both the Webapp (React) and SDK (vanilla)?
  • How do we persist saved Prompts?

We need to be able to express Prompts in a common language that both React and VanillaJS can render. Fortunately for us, we can make use of the newest kid on the block: Web Components ✨. They are supported natively meaning we can use them freely without any dependencies or complicated setups.

As for saving prompts, we need the ability to serialise and deserialise them onto their basic building blocks. These blocks need to be expressive enough to capture the customisation fields - say color: red.

That’s it! We persist the serialised version of a prompt, and whenever we need to display it, we deserialise back and render it using web components.

Now that you know what we’re building, you might be interested in how we go about it!

Demo driven development

We hope you enjoyed the read 😊