Building a globally accessible flow
At Persona, we're building a safer and more secure internet. Our customers use the Persona SDK across countries, industries, and use cases to securely collect sensitive information from end-users.
How we partner with customers to prove an individual earned an online course's certification is completely different from how we partner with customers to ensure someone can find a trustworthy babysitter. This means the Persona app must support a wide range of interactions — from collecting utility bills to recording a selfie video to prove liveness. And because access is so critical to online identity, we made sure Persona works on whatever surface end-users need it to, whether that's a web browser or a customer's native mobile app.
As we built more and more solutions across fraud, compliance, and trust, we realized that senselessly adding configurations would eventually fall apart. In fact, making the Persona app more configurable wasn't enough — we had to design and construct an app builder. This app builder now lets us build any flow rooted on security and trust with the power of the Persona platform backing it. We're currently working on extending this full power to customers so our customers can design their own flows to fight fraud and earn trust with consumers.
Why server-driven UI?
Before server-driven UI, we passed a large configuration data blob to the client — a standard web practice. But adding interaction or visual configurations meant creating new keys in the configuration data blob, which quickly became unsustainable.
This largely comes from the web client model, where client code has more flexibility than server code. As a result, complexity is pushed to the client.
In our case, customers integrate our native SDKs directly into their app. If we wanted to force updates, we'd have to ask customers to spend engineering time updating their apps, then force their end-users to update as well — which is rather unreasonable. Because we can't update our native mobile clients, they are even less flexible than server code and therefore reverse the flow of complexity despite sharing logic with web client code.
As our server code got more complex, we searched for a tighter framework that would simplify our backend but still let us visualize all sorts of screens and interactions. Thus, we ended up on server-driven UI. Server-driven UI better defines responsibilities on the server and enables more powerful UIs on all clients: mobile and web. Instead of passing giant configuration data blobs to clients, our server renders and passes client-component representations. This lets our backend scale well with added configurations, and also lets us piece together screens and elements however we need.
Taking server-driven UI one step further
Unlike most implementations of server-driven UI, our app's screens and components are also fully configured by our customers. In order to let customers build their own screens, we created separate "Customer" and "Client" components. For example, customers can add an Address customer component to a screen. The server dynamically renders this customer component into multiple Text client components depending on the selected country. In the example below, the first field (also used for autocomplete) is street in the United States but postal code in the United Kingdom. State is also removed and apt / suite is added as a separate component.
This implementation allows for strong configurability and future flexibility. Because we handle the customer to client component rendering, our customers don't need to understand address internationalization. They get it out of the box. We're still working on applying this approach to other flow elements, from simple date inputs to interactive guidance for document captures.
There are also many other opportunities to create a wonderful experience with this system:
Instantaneous form validation
JsonLogic enables client-side validation that is consistent across platforms. It also defines a standard representation for logic expressions which we let customers attach to customer component. Public libraries are available for evaluating these expression client-side, enabling instantaneous form validation.
In certain situations, we want the server to send different components to different clients. Mobile clients typically have better cameras, so we often ask individuals on web to SMS themselves a link to continue on a mobile device. This is available through a smart component that customers can include in flows that need high quality camera uploads. If the server detects that the client is on a PC, it renders a client component with that option. If the client is already on a mobile device, no client component is sent.
Other future opportunities include taking advantage of device-specific sensors, such as using mobile devices to scan passport NFCs.
Versioning for backwards compatibility
The customer to client component rendering gives us more flexibility for versioning as well. For example, newer clients may contain smarter address components with autocomplete or other features. The server would render according to the client's version. And if an older client does not have the new address client component, then the server would continue to send it simple text client components. From our customer's point of view, they're using a single address customer component, and they don't need to carefully consider versioning when building their flow.
So what's next?
We'll continue pushing the bounds of interactivity and experience in our app builder. For example, changing country should re-render address components on the same page. This alone is a challenging problem because of the design and usability concerns — we'd need to decide what to do with already-inputted text, too.
Extending this approach to new component types is a challenge as well since operating systems have different design guidelines. How does this work for more complex components like location selection on a map? What about signature collection?
There's definitely a lot more to explore here now that we have the initial framework for server-driven UI set up. Going forward, we'll continue expanding and aiming for a level of polish that not only communicates the intentional thought and care we place into our product, but also elevates our customers as well.