Flexibility first: scaling our white-label solution for industry partners
When our team was tasked with building a new white-label solution, we were given a few key objectives — it had to be performant, scalable, and highly customisable in terms of look and feel. Essentially, we needed to develop the necessary mechanisms to serve multiple partners from a single code repository, all with their own branding, copy, catalogue and domain needs.
For the frontend architecture, we decided to use Nuxt.js, the Vue meta-framework, which is battle-tested and standardised across most of our digital platforms in TUI Musement. We also opted to build it as a server-side rendered (SSR) application since this would allow for the highest level of flexibility in deciding what needs to be initialised on the server and what could be left to the client-side, not to mention the performance benefits gained from pre-rendering content.
To satisfy the requirement of serving multiple partners from a single repository, we decided to create a so-called brand configuration object, comprising visibility flags, metadata, styling, and language and currency options, among others.
What we ended up with, looks a bit like this:
For each partner, we would create and store this unique object in our custom backend server, where the frontend would be able to retrieve it, based on some parameters.
The next challenge was to decide on said parameters. After a few iterations, we decided that one of the key requirements was to store the domain info in the brand configuration and check it against where the request originated from. This was mainly because we needed to serve requests from .com
addresses as well as language-based ones, such as .it
or .co.th.
, as well as syncing the request with the correct market/language/currency when the customer lands on our white-label site.
In Nuxt.js, this can be achieved by the nuxtServerInit
function, which runs on the server and is called with the context, allowing us to hook into useful things like the route and state management, in order to dispatch actions or commit mutations, and grab the language code from the URL query parameters.
An oversimplification of retrieving the brand config can be visualised like this:
nuxtServerInit function
Initial complications rose from not knowing exactly which customisation options would actually be relevant for the partners, and we had to resist the urge to try and predict these features internally, relying instead on the feedback from the partnership team, based on input from the partners themselves.
This meant a lot of back and forth between setting static defaults in the project and moving things to the brand configuration. Thankfully, our backend was adaptable enough to support this without too many issues. According to my estimations, by the end of developing the minimal viable product (MVP), we had changed around 90% of the original shape of the brand config object because the scope of customisation options kept rising steadily throughout development.
At this point, the performance was not stellar because we had initialised everything on the server, including internationalisation, cart creation, etc. We re-analysed and started moving everything that wasn’t critical over to the client, to reduce initial load time. Along with setting caching policies for each individual endpoint, we were able to increase performance considerably.
Post-MVP, the engineering team has concentrated on steadily increasing customisation options to the platform.
The way our Musement catalogue works with white-labels, is by essentially creating custom markets where we can map any of our activities to them. They can be customised to any degree, e.g., we can map Spanish activities for the Italian market, whitelist, or block certain destinations or activities. In practice, this means that we can support partners at any scale, from having operations in a few markets to ones with a global presence.
“Another thing we are doing to improve user experience is implementing deep links, which allow us to use hyperlinks that link to specific pages in the application, so a partner can provide a URL link and put some parameters in the query string according to our API documentation, and we can translate that information to something on our site,” says Michał Tomsia, Senior Software Engineer.
“For example, an airline partner can redirect the customer to the destination page of where they booked their flight to, with pre-filled dates, email addresses, or the number of tickets, to book activities for that location.”
Despite the ongoing global pandemic, things are also picking up speed from the product roadmap and customer pipeline perspective.
“During the first quarter, while still developing the platform, we were able to launch a single big client, and by the next one we had already managed six,” says Nicola Pacini, Digital Product Manager.
“We are gaining a lot of speed in releasing new sites and because of this, we can spend the time on further improving the platform, with a focus on improving the onsite customer experience in order to increase conversion rates. The next step is to create a playground, where our partners can play around with the site customisation options in real time, without having to wait for designer mock-ups.”