How we power 1.5Bn+ unique checkout experiences: Inside our SDK

12 min read Mar 2025

Shooting and landing on two north stars!

Improving Payment experiences, making it easier for everyone to pay, and making it smooth for those collecting payment across geographies, has been at the core of what Juspay has stood for over the last decade. Some of the technology choices we took to enable this led us to building one of most widely used payment software. A decade ago, smartphones and internet connectivity was at an inflection point. We bet on this trend early. We realised the best payment experiences would happen on phones, and to improve user experience we had to run software on edge devices.

To do this we built a Software Development Kit (SDK) that simplifies the integration process for merchants while ensuring a smooth payment experience for end-users. This blog dives into the architecture of our SDK, the challenges we’ve faced, and the innovative solutions we’ve implemented to make payments faster and more efficient.Juspay’s SDKs are key tools that help merchant applications interact with our Orchestration Layer. It’s Juspay’s inside man, getting the job done for the merchant from the checkout page onwards.From the early days of building an SDK, to today, we’ve worked with twin north star goals, Performance and Adoption. The payment page is a breeding ground for micro changes that can drive business outcomes. How to ensure users see the right payment page, but also don't wait for the right assets to download every single time, is THE question we try to answer in every iteration of the SDK.

First Up: Why do we need an SDK?

Merchants integrating payment solutions often face a difficult task: integrating multiple APIs, each handling different aspects of the payment process. This not only increases development time but also introduces complexity and potential points of failure. To address this, we set out to create an SDK (software development kit) that acts as a plug-and-play solution , abstracting away the complexity and allowing merchants to go live faster.

The SDK is a piece of code that resides inside the merchant’s app, when they integrate with Juspay. Our SDK is designed to handle everything from payment processing to UI rendering, ensuring that merchants don’t have to worry about integrating 25 different APIs. Instead, they get a single, lightweight SDK that does it all.

The Architecture: Native SDK + JavaScript Layer

At its core, our SDKs are built on a two-layer architecture: a native layer and a JavaScript layer .

The Native Layer

The native layer is the foundation of the SDK. It’s lightweight, weighing in at just 300-350 KB , and handles basic operations like:

  • Network calls : Making internet requests to process payments.
  • File system operations : Downloading, updating, and removing files.
  • Logging : Writing logs to the device’s file system
  • Rendering : Rendering UI for the different payment flows and platforms (Android / iOS / Web)

The native layer is kept minimal to ensure performance and efficiency.

The JavaScript Layer

On top of the native layer sits the JavaScript layer , which houses most of the business logic . This layer is where we control the majority of the SDK’s functionality, including:

  • UI customization : Changing colors, enabling features like OTP autofill, and more.
  • Payment logic : Handling different payment methods, app switches, and callbacks.

The JavaScript layer is designed to be flexible and modular. We’ve broken it down into microservices , each handling a specific functionality. For example:

  • HyperCheckout : Handles the payment page UI.
  • EC (Express Checkout) : Manages backend calls for payment processing.
  • UPI Plugin : Handles UPI app switches and callbacks.
  • Godel : Automatically reads and submits OTPs for faster payments.

These microservices are orchestrated by HyperOS, which acts as the central manager, ensuring that all components work together seamlessly. For example, when a user chooses a google pay transaction, HyperOS ensures the UPI Plugin, takes the user to the UPI app she chooses, and records the end of that transaction, and brings them back to the payment completion page. Whereas for a card transaction, it fires up the Microservice called Godel, which is like a mini web browser to bring native transaction experience.

This architecture helps Juspay push changes OTA (over the air), and ensures the merchant does not need to make new app releases for every minor change in the payment experience. For example, if the payment methods are re-ordered by the merchant, it is stored as a configuration change in one of the microservices. When the user opens up the app, the latest changes are downloaded by the SDK, and then displayed to the user.

To achieve cross-platform compatibility while keeping the SDK lightweight, we use Presto—Juspay’s in-house app development framework. Unlike traditional cross-platform solutions like React Native or Flutter, Presto is optimized for performance-critical applications like payments. With Presto we were also able to make our SDK truly lightweight. Upto 5-10X smaller compared to React Native or flutter. It allows us to write once and deploy seamlessly across Android, iOS, and Web, reducing the need for maintaining multiple codebases

The Challenge

This also leads to a challenge. If the SDK has to download all the latest challenges every single time the user opens the app, that's a challenge. Simply speaking, users could drop off, because the payment page did not load in time. The next section discusses how we continue to address these challenges.

Pushing the boundaries of Performance and Adoption

Optimizing downloads with manifest

Iteration 1 - Initiate + Process

We want our SDK to perform well under all conditions. Especially during the initial download and load phase. When a user opens an app for the first time, the SDK needs to download necessary files, which can be upto a few MB in size. This download time can lead to user drop-offs, especially if the internet connection is slow.

To address this, we implemented a two-step process :

1. Initiate : Boot up the SDK and start downloading necessary files. This typically happens in the background when the User opens up the app.

2. Process : Load the SDK and begin payment processing. This happens when the user clicks on “Pay now” or equivalent CTAs.

However, we realized that waiting for the entire download to complete before loading the SDK was not ideal. Instead, we adopted a parallel download and load approach. The SDK starts loading immediately, even as the download continues in the background. This ensures that users can start using the app without waiting for the full download to complete. With this approach we realised a 50-60% reduction in Latency of Payment Page opening.

Iteration 2 - Optimizing Downloads with Manifests

To further optimize the download process, we introduced a manifest system . The SDK keeps track of the files it has downloaded and their hashes . Before downloading a file, it checks the hash against the one stored in the cloud. If the hashes match, the SDK skips the download, saving time and bandwidth.

This approach not only improves performance but also reduces costs by minimizing unnecessary downloads. With the Manifests we achieved a remarkable 0 duplicate downloads.

Iteration 3 - Dynamic SDK

With Dynamic SDK every time a merchant rebuilds their app, the latest versions of the microservices are bundled into the app. This ensures that the app always has the most up-to-date features without requiring runtime updates. This ensures the latest changes are always available without needing runtime downloads. Even when the changes are not loaded in time, the merchants always have a fall back version that loads, without waiting for downloads. By bundling the latest assets of a merchant with the Native layer, in essence we have 1 SDK that acts like ‘n’ Unique SDKs for each and every merchant. With the first two iterations, the balance shifts towards adoption of latest changes, since there is a download of latest configs every single time there are changes. With this iteration, the balance is more towards performance. Since the latest version of the Microservices are bundled together with the SDK, there is no need for new downloads every single time.

Prod as Playground

While various iterations of the SDK have pushed the boundaries on Performance and Adoption, we have parallelly implemented systems that can allow merchants to safely test changes before releasing them to their wider user bases. We introduced a CUG (Controlled User Group) app. This app allows merchants to test changes in a production environment without releasing them to all users. Once the changes are validated, they can be rolled out to the broader user base.

On top of this, all our releases are through an A/B engine, which staggers changes to a select percentage of users, monitors success metrics like Success rates and latency before rolling out to all users. When there are issues spotted, the system falls back to the last stable versions.

Outlook for the future

These are some ideas currently in brain storming, to further improve Performance and Adoption at the same time.

Splitting the Microservices for Faster Adoption

While our current architecture works well, we’re constantly looking for ways to improve. One area we’re focusing on is splitting the Microservices into smaller, feature-based files . Currently, the Microservices are single, monolithic packages, which means users have to download the entire package even if there is a change in a small part of it.

By splitting the Microservices into smaller files, we can reduce the initial download size. For example, if only the card payment screen has changed, we can release just that part of the HyperCheckout microservice, rather than the entire package. This approach will significantly improve adoption rates, especially for users with slower internet connections.

Splitting the Microservices for Faster Adoption

Timeouts

Another improvement we’re working on is introducing timeouts for downloads. Our current implementation of Dynamic SDK loads the latest bundled versions, before downloading changes. We are experimenting with loading the changes with a time cut off before rendering the payment page, to further push the boundaries on Adoption.

 introducing timeouts for downloads

Conclusion: A Seamless Payment Experience

At Juspay, our goal is to make payments as seamless as possible for both merchants and end-users. Aligning with our early bet on edge devices, our SDK’s architecture, with its native and JavaScript layers, microservices, and orchestration system, is designed to achieve this goal. Over the years we have kept pace with innovations in these devices and the larger payment ecosystem by continuously optimizing performance, reducing download sizes, and giving merchants control over updates. We will continue to find creative solutions to keep improving payment experiences for customers worldwide.