Tag Archives: case study

SoundCloud supported more screens using 45% less code with Jetpack Compose

Posted by Chris Arriola, Developer Relations Engineer and Nick Butcher, Product Manager for Jetpack Compose

As one of the largest audio streaming platforms in the world, SoundCloud supports a network of creators who use its service to upload and promote their music. SoundCloud’s developers are always exploring ways to improve its user experience, which means going beyond simply building the best mobile app. The team also wants to make SoundCloud available on as many form factors as possible so users can easily access and listen to SoundCloud in any situation and on the devices that work best for them.

That’s why the SoundCloud team adopted Jetpack Compose, Android’s modern declarative toolkit for building native UI. Compose enabled SoundCloud engineers to not only expand the app to more form factors, but also streamline new feature development—in some cases reducing nearly half the code.

Compose helped us reach new users and markets, ultimately increasing our global reach” — Vitus Ortner, Android engineer at SoundCloud

Simplified UI development with Compose

Before migrating to Compose, building UI was much slower for SoundCloud developers because they had to constantly switch context between Kotlin and XML. This also made managing and maintaining its design system much more difficult. The team’s engineers wanted to find a simpler way to write code, and they knew Compose would help them get there.

“We started adopting Compose to quickly build dynamic layouts using Kotlin, the language we love,” said Vitus Ortner, an Android engineer at SoundCloud. “We wanted to empower our engineers to effectively create rich UIs through Compose.”

SoundCloud engineers overhauled the app’s design system with Compose and can now build new features using 45% less code on average. Compose’s concise Kotlin syntax and its ability to create reusable UI made design and maintenance much easier for the team. Prototyping new features was also simpler thanks to Compose’s declarative approach, as well as its live edit and UI preview features.

“We implemented a new content discovery feature with an interactive vertical feed layout. We used Compose to prototype, and it enabled us to iterate fast even when we changed our design ideas daily,” said Vitus. “That wouldn’t have been possible with Views.”

Compose’s interoperability with Views made it easier for developers to migrate SoundCloud’s design system to the new toolkit because they could do it gradually. Because SoundCloud uses a model–view–viewModel architecture, developers could reuse the app’s old view models in the new Compose framework. This meant they only needed to migrate the app’s View-based layouts to Compose, rather than rewrite the entire UI layer.

“Compose helped us reach new users and markets, ultimately increasing our global reach” — Vitus Ortner, Android engineer at SoundCloud

Optimizing for more form factors with Compose

Switching to Compose enabled developers to do more than streamline the app’s codebase. It also made supporting multiple form factors easier. With Compose, SoundCloud engineers were able to more easily bring the app to tablets, TVs, cars, and wearables.

“We’re using Compose across all form factors in the Android ecosystem,” said Vitus. “We implemented our Wear OS and TV apps from the ground up with Compose, which allowed us to rapidly iterate and ship new products in a fraction of the time it would have taken before.”

To adapt the mobile experience to a variety of screen sizes while maintaining interoperability with existing code, SoundCloud developers provide different XML layouts to combine existing View code with newer Compose components. Easy-to-implement features like this helped the team quickly build experiences across different devices, including optimizing SoundCloud for cars and tablets.

With these improvements, SoundCloud engineers built their Wear OS app and TV app from the ground up in just four months using Compose. According to Vitus, this “would’ve been unthinkable” using their previous system.

“Our mobile Compose skills transferred directly to Compose for other form factors,” said Vitus. “The concepts and most APIs are the same across form factors. We still needed to learn some form factor-specific APIs, like ScalingLazyColumn for Wear OS and TvLazyColumn for TVs.”

UI example

Future investment in Compose

By migrating its Android app to Compose, SoundCloud developers improved productivity, simplified the app’s code, and established smoother development processes for new features and experiences. Switching to Compose also helped SoundCloud expand to more form factors, creating new ways for users to access the platform.

“Compose helped us reach new users and markets, ultimately increasing our global reach,” said Vitus. “We're fully committed to Compose and plan to use it for all projects in the future.”

Get started

Optimize your UI development with Jetpack Compose.

Google Drive cut code and development time in half with Jetpack Compose and new architecture

Posted by Nick Butcher – Product Manager for Jetpack Compose, and Florina Muntenescu – Developer Relations Engineer

As one of the world’s most popular cloud-based storage services, Google Drive lets people do more than just store their files online. With Drive, users can synchronize, share, search, edit, and even pin specified files and content for safe and secure offline use.

Recently, Drive’s developers revamped the application’s home screen to provide a more seamless experience across devices, matching updates made to Google Drive’s web version. However, the app’s previous architecture and codebase would’ve prevented the team from completing the updates in a timely manner.

Instead of struggling with the app’s previous tech stack to implement the update, the Drive team rebuilt the home page from the ground up using Android’s recommended architecture and Jetpack Compose, Android’s modern declarative toolkit for creating native UI.

Compose, combined with architecture improvements, cut our development time nearly in half.” — Dale Hawkins, Senior software engineer and tech lead at Google Drive

Experimenting with Kotlin and Compose

The Drive team experimented with Kotlin — which the Compose toolkit is built with — for several months before planning the app’s home screen rebuild. Drive’s developers liked Kotlin’s improved syntax and null enforcement, making it easier to produce code.

“We had been using RxJava, but started looking into replacing that with coroutines,” said Dale Hawkins, the features team lead for Google Drive. “This led to a more natural alignment between coroutines and Jetpack Compose. After a deep dive into Compose, we came away with a clear understanding of how Compose has numerous benefits over the Views-based approach.”

Following the Kotlin exploration, Dale experimented with Jetpack Compose. “I was pleased with how easy it was to build the UI using Compose. So I continued the experiment after that week,” said Dale. “I eventually rewrote the feature using Compose.”

Using Compose

Shortly after experimenting with Jetpack Compose, the Drive team decided to use it to completely rebuild the app’s home screen UI.

“We wanted to make some major changes to match the ones being done for the web version, but that project had a several-month head start. We wanted to release the Android version shortly after the web changes went live to ensure our users have a seamless Google Drive experience across devices,” said Dale.

The Drive team's experimentation and testing with Jetpack Compose showed that the new toolkit was powerful and reliable and that it would enable them to move faster. With this in mind, the Drive team decided to step away from their old codebase and embrace Jetpack Compose for the app’s home screen update. Not only would it be quicker and easier, but it would also better prepare the team to easily make future UI changes.

Using Android’s guidance for architecture

Before going all-in with Jetpack Compose, Drive developers wanted to restructure the application by implementing a completely new app architecture. Drive developers followed Android’s official architecture guidance to apply structural changes, paving the way for the new Kotlin codebase.

“The recommended architecture reinforces good separation between layers,” said Quintin Knudsen, an Android engineer for Google Drive. “We work in a highly dynamic environment and need to be able to adjust to any app changes. Using well-defined and independent layers helps isolate any changes or UI requirements. The recommendations from Android offered sound ways to structure the layers.” With a clear separation between the app’s data and UI layers, developers could work in parallel to significantly speed up testing and development.

Drive developers also relied on Mappers and UseCases when creating the new architecture. These patterns allowed them to create flexible code that is easier to manage. They also exposed flows from their ViewModels to make the UI respond immediately to any data changes, making it much simpler to implement and understand UI updates.

Less code, faster development

With the app’s newly improved architecture and Jetpack Compose, the Drive team was able to develop the app’s new home screen in less than half the time that they expected. They also implemented the new code and finished quality assurance testing nearly seven weeks ahead of schedule.

“Thanks to Compose, we had the groundwork done within a couple of weeks. We delivered a great implementation over a month ahead of schedule, and it’s been praised by product, UX, and even other engineering teams,” said Dale.

Despite having fewer features, the original home screen required over 12,000 lines of code. The new Compose-based home screen has many new features and only required 5,100 lines of code—a 57% reduction. Having less code makes it much easier for developers to maintain the app and implement any updates.

Testing the new UI in Jetpack Compose also required significantly less code. Before Compose, Drive developers used roughly 9,000 lines of code to test about 62% of the UI. With Compose, it took only 2,200 lines to test over 80% of the new UI.

The original home screen required over 12,000 lines of code. The Compose-based home screen only required 5,100 lines of code. That’s a 57% reduction.” — Dale Hawkins, Senior software engineer and tech lead at Google Drive

Looking forward

A new and improved app architecture paired with Jetpack Compose allowed Drive developers to rebuild the app’s home screen UI faster and easier than they could’ve imagined. The Drive team plans to expand its use of Compose within the application for things like supporting large dynamic displays and text resizing.

“As we work on new projects, we’re taking the opportunity to update older UI code to make use of our new architecture and Compose. The new code will be objectively better and features will be easier to write, test, and maintain,” said Dale.

Get started

Improve app architecture using Android’s official architecture guidance and optimize your UI development with Jetpack Compose.

PJRT Plugin to Accelerate Machine Learning

PJRT is an open, stable interface for device runtime and compiler, which simplifies ML hardware and framework integration. With PJRT, ML frameworks become hardware-agnostic and ML hardware becomes pluggable. For the ML developer, it simplifies the adoption of new ML hardware and models become more portable. This addresses ML infrastructure fragmentation across frameworks, compilers and runtimes enhancing the industry’s ability to productionize ML-driven advancements with velocity and at scale.

This article provides an overview of what building a PJRT plugin entails, how frameworks (and models) can use this plugin, and some updates on the PJRT API. PJRT is now used by a growing spectrum of hardware: Apple silicon, Google Cloud TPU, NVIDIA GPU, and Intel Max GPU. We also share a spotlight on Apple’s adoption of PJRT with some details on the workflow and performance.

If you’re developing an ML hardware accelerator or developing your own compiler and runtime, check out the PJRT source code on GitHub and sign up for the PJRT mailing list to quickly bootstrap your work.

What’s in a PJRT Plugin

PJRT was introduced to simplify the growing complexity of ML workload execution across hardware and frameworks. PJRT (used in conjunction with StableHLO) is a stable interface for device runtime and compiler, which abstracts away device specific implementations from frameworks.

An implementation of the PJRT API is called a PJRT plugin, which is usually a Python package for seamless ML model developer experience. To build a PJRT plugin for a hardware target, the following methods need to be implemented:

  • Compile: compile (program) -> executable
  • Runtime: execute (executable, arguments) -> results
  • Memory management: transfer buffer from host to device, device to host, device to device, as well as buffer management such as buffer donation
  • Topology information such as the platform, how many accelerators and how are they attached.

ML frameworks will discover and load one or multiple PJRT plugins, and call the PJRT API to compile and execute the model. The PJRT plugins may be required to register to the ML frameworks depending on the specific discovery mechanism the framework uses.

API Updates

Versioning and ABI Compatibility

PJRT API has a major version and a minor version. If the framework is newer than the plugin, the framework provides a N-week (N=6 today) forwards compatibility window for minor version updates. The major version updates will be a coordinated update. Frameworks will not support plugins with a lower major version. If the plugin is newer than the framework, plugins will define their own backward compatibility policy.


A PJRT client is per node, and the plugin may need some way to communicate among nodes in a distributed workload. The framework can pass in key-value store callbacks to the plugin. The plugin can use them to bootstrap multi-node initialization and other coordination needs. An example with the NVIDIA GPU CUDA plugin is as follows:

  • JAX starts a distribution service and provides key-value store callbacks.
  • NVIDIA GPU CUDA plugin uses these callbacks to (1) generate global PJRT device topology that includes PJRT device information from all nodes, and (2) generate NCCL ids.


A few C APIs were added to PJRT to support DLPack.

  • PJRT_Client_CreateViewOfDeviceBuffer supports receiving buffers from DLPack.
  • Exporting buffers to DLPack requires: PJRT_Buffer_IncreaseExternalReferenceCount, PJRT_Buffer_DecreaseExternalReferenceCount to get a PJRT_Buffer_OpaqueDeviceMemoryDataPointer.


PJRT API provides an extension mechanism that the plugin can provide extensions which are optional or experimental features. These extensions can have their own compatibility guarantee and do not need to support the ABI compatibility of PJRT API.

Industry Adoption

PJRT is the only interface for JAX, the primary interface for TensorFlow and fully supported for PyTorch through PyTorch/XLA. PJRT is not tied to a specific compiler and runtime. The toolchain-independent architecture and open-source availability as part of the OpenXLA Project allows it to be leveraged by any hardware, framework or compiler, with extensibility for unique features. This has allowed PJRT to be adopted by various industry partners through close collaboration. A brief account of Apple’s adoption of PJRT follows.

JAX on Apple Silicon

Apple’s PJRT plugin for the Metal training backend accelerates JAX models on Apple silicon and AMD GPUs. This empowers any ML developers to leverage the full potential of Apple silicon and AMD GPUs on their Apple hardware to accelerate JAX models for faster experimentation. The integration and user experience to accelerate JAX on Apple silicon GPUs is similar to the existing PyTorch and TensorFlow implementations.

The Metal plug-in uses the OpenXLA compiler and PJRT runtime to optimize and accelerate JAX workloads on GPU. When a JAX program is executed, the JAX graph is lowered into StableHLO, which is then passed to PJRT for compilation and execution. The StableHLO is converted to MPSGraph executables and the Metal runtime APIs are invoked to dispatch to the GPU.


The Metal backend with PJRT plugin provides impressive performance speedup for JAX. On an Apple MacBook Pro with M2 Max, training common networks in JAX see performance speedups of up to 28x, with an average of 10x over a CPU baseline. This empowers any ML developer to leverage the full potential of Apple Silicon on their Apple hardware to accelerate JAX models for faster experimentation.

graph of performance speedups of up to 28x on Apple MacBook Pro with M2 Max over CPU for JAX training.
Figure 1: Performance speedups of up to 28x on Apple MacBook Pro with M2 Max over CPU for JAX training.

Getting Started

Adding Metal support to JAX is as simple as a single pip install:

python -m pip install jax-metal
python -c 'import jax; print(jax.numpy.arange(10))'

For more details on environment setup and installation of JAX on Apple hardware, please refer to the Metal Developer Resources page.

Google Cloud TPU

PJRT is the default runtime for PyTorch 2.0 on Google Cloud TPU. GitHub Readme has more details.


The NVIDIA GPU CUDA implementation in JAX is extracted and packaged as a PJRT plugin. The ML model developers can install the NVIDIA GPU CUDA plugin from pypi. This plugin uses the newly added features such as multi-node, DLPack, and extensions.

Intel GPU

Intel is leveraging PJRT in Intel® Extension for TensorFlow to provide the Intel GPU backend for TensorFlow, JAX and PyTorch. The example of executing a JAX program on Intel GPU demonstrates how this greatly simplifies the framework and hardware integration.

PJRT Resources

PJRT is available on GitHub: source code for the API, integration guides and issues. If you develop ML frameworks, compilers, runtimes or are interested in improving portability of workloads across hardware, we want your feedback. We encourage you to contribute code, design ideas and feature suggestions. We also invite you to join the PJRT mailing list to stay updated with the latest product and community announcements and to help shape the future of an interoperable ML infrastructure.


Chalana Bezawada, Daniel Doctor, Kulin Seth, Shuhan Ding from Apple 
Penporn Koanantakool, Peter Hawkins, Skye Wanderman-Milne, Xiao Yu from Google.

By Aman Verma – Product Manager, Machine Learning Infrastructure, Google and Jieying Luo – Software Engineer, Machine Learning Infrastructure, Google

Embracing Android 14: Meta’s Early Adoption Empowered Enhanced User Experience

Posted by Terence Zhang – Developer Relations Engineer, Google; in partnership with Tina Ho - Partner Engineering, TPM and Kun Wang – Partner Engineering, Partner Engineer

With the first Developer Preview of Android 15 now released, another new Android release that brings new features and under-the-hood improvements for billions of users worldwide will be coming shortly. As Android developers, you are key players in this evolution; by staying on top of the targetSDK upgrade cycle, you are making sure that your users have the best possible experience.

The way Meta, the parent company of Instagram, Facebook, WhatsApp, and Messenger, approached Android 14 provides a blueprint for both developer success and user satisfaction. Meta improved their velocity towards targetSDK adoption by 4x, and so to understand more about how they built this, we spoke to the team at Meta, with an eye towards insights that all developers could build into their testing programs.

Meta’s journey on A14: A blueprint for faster adoption

When Android 11 launched, some of Meta’s apps experienced challenges with existing features, such as Chat Heads, and with new requirements, like scoped storage integration. Fixing these issues was complicated by slow developer tooling adoption and a decentralized app strategy. This experience motivated Meta to create an internal Android OS Readiness Program which focuses on prioritizing early and thorough testing throughout the Android release window and accelerating their apps’ targetSDK adoption.

The program officially launched last year. By compiling apps against each Android 14 beta and conducting thorough automated and smoke tests to proactively identify potential issues, Meta was able to seamlessly adopt new Android 14 features, like Foreground Service types and send timely feedback and bug reports to the Android team, contributing to improvements in the OS.

Meta also accelerated their targetSDK adoption for Android 14—updating Messenger, Facebook, and Instagram within one to two months of the AOSP release, compared to seven to nine months for Android 12 (an increase of velocity of more than 4x!). Meta’s newly created readiness program unlocked this achievement by working across each app to adopt latest Android changes while still maintaining compatibility. For example, by automating and simplifying their SDK release process, Meta was able to cut rollout time from three weeks to under three hours, enhancing cooperation between individual app teams by providing immediate access to the latest SDKs and allowing for rapid testing of new OS features. The centralized approach also meant Threads adopted Android 14 support quickly despite the fast-growing new app being supported by a minimal team.

Reaping the rewards: The impact on users

Meta's early targetSDK adoption strategy delivers significant benefits for users as well. Here's how:

    • Improved reliability and compatibility: Early adoption of Android previews and betas prevented surprises near the OS launch, guaranteeing a smooth day-one experience for users upgrading to the latest Android version. For example, with partial media permissions, Meta's extensive experimentation with permission flows ensured “users felt informed about the change and in control over their privacy settings,” while maximizing the app's media-sharing functionality.

    • Robust experimentation with new release features: Early Android release adoption gave Meta ample time to collaborate across privacy, design, and content strategy teams, enabling them to thoughtfully integrate the new Android features that come with every release. This enhanced the collaboration on other features, allowing Meta to roll out Ultra HDR image experience on Instagram within 3 months of platform release in an “Android first” manner is a great example of this, delighting users with brighter and richer colors with a higher dynamic range in their Instagram posts and stories.
Meta's adoption of Ultra HDR in Android 14 brings brighter colors and dynamic range to Instagram posts and stories.
Meta's adoption of Ultra HDR in Android 14 brings brighter colors and dynamic range to Instagram posts and stories.

Embrace the latest Android versions

Meta's journey highlights the compelling reasons for Android developers to adopt a similar forward-thinking mindset in working with the Android betas:

    • Test your apps early: Anticipate Android OS changes, ensuring your apps are prepared for the latest target SDK as soon as they become available to create a seamless transition for users who update to the newest Android version.

    • Utilize latest tools to optimize user experience: Test your apps thoroughly against each beta to identify and address any potential issues. Check the Android Studio Upgrade Assistant to highlight major breaking changes in each targetSDKVersion, and integrate the compatibility framework tool into your testing process to help uncover potential app issues in the new OS version.

    • Collaborate with Google: Provide your valuable feedback and bug reports using the Google issue tracker to contribute directly to the improvement of the Android ecosystem.

We encourage you to take full advantage of the Android Developer Previews & Betas program, starting with the newly-released Android 15 Developer Preview 1.

The team behind the success

A big thank you to the entire Meta team for their collaboration in Android 14 and in writing this blog! We’d especially like to recognize the following folks from Meta for their outstanding contributions in establishing a culture of early adoption:

    • Tushar Varshney - Partner Engineering, Partner Engineer
    • Allen Bae - Partner Engineering, EM
    • Abel Del Pino - Facebook, SWE
    • Matias Hanco - Facebook, SWE
    • Summer Kitahara - Instagram, SWE
    • Tom Rozanski - Messenger, SWE
    • Ashish Gupta - WhatsApp, SWE
    • Daniel Hill - Mobile Infra, SWE
    • Jason Tang - Facebook, SWE
    • Jane Li - Meta Quest, SWE

HealthPulse AI Leverages MediaPipe to Increase Health Equity

A guest post by Rouella Mendonca, AI Product Lead and Matt Brown, Machine Learning Engineer at Audere

Please note that the information, uses, and applications expressed in the below post are solely those of our guest authors from Audere.

About HealthPulse AI and its application in the real world

Preventable and treatable diseases like HIV, COVID-19, and malaria infect ~12 million per year globally with a disproportionate number of cases impacting already underserved and under-resourced communities1. Communicable and non-communicable diseases are impeding human development by their negative impact on education, income, life expectancy, and other health indicators2. Lack of access to timely, accurate, and affordable diagnostics and care is a key contributor to high mortality rates.

Due to their low cost and relative ease of use, ~1 billion rapid diagnostic tests (RDTs) are used globally per year and growing. However, there are challenges with RDT use.

  • Where RDT data is reported, results are hard to trust due to inflated case counts, lack of reported expected seasonal fluctuations, and non-adherence to treatment regimens.
  • They are used in decentralized care settings by those with limited or no training, increasing the risk of misadministration and misinterpretation of test results.

HealthPulse AI, developed by a digital health non-profit Audere, leverages MediaPipe to address these issues by providing digital building blocks to increase trust in the world’s most widely used RDTs.

HealthPulse AI is a set of building blocks that can turn any digital solution into a Rapid Diagnostic Test (RDT) reader. These building blocks solve prominent global health problems by improving rapid diagnostic test accuracy, reducing misadministration of tests, and expanding the availability of testing for conditions including malaria, COVID, and HIV in decentralized care settings. With just a low-end smartphone, HealthPulse AI improves the accuracy of rapid diagnostic test results while automatically digitizing data for surveillance, program reporting, and test validation. It provides AI facilitated digital capture and result interpretation; quality, accessible digital use instructions for provider and self-tests; and standards based real-time reporting of test results.

These capabilities are available to local implementers, global NGOs, governments, and private sector pharmacies via a web service for use with chatbots, apps or server implementations; a mobile SDK for offline use in any mobile application; or directly through native Android and iOS apps.

It enables innovative use cases such as quality-assured virtual care models which enables stigma-free, convenient HIV home testing with linkage to education, prevention, and treatment options.

HealthPulse AI Use Cases

HealthPulse AI can substantially democratize access to timely, quality care in the private sector (e.g. pharmacies), in the public sector (e.g. clinics), in community programs (e.g. community health workers), and self-testing use cases. Using only an RDT image captured on a low-end smartphone, HealthPulse AI can power virtual care models by providing valuable decision support and quality control to clinicians, especially in cases where lines may be faint and hard to detect with the human eye. In the private sector, it can automate and scale incentive programs so auditors only need to review automated alerts based on test anomalies; procedures which presently require human reviews of each incoming image and transaction. In community care programs, HealthPulse AI can be used as a training tool for health workers learning how to correctly administer and interpret tests. In the public sector, it can strengthen surveillance systems with real-time disease tracking and verification of results across all channels where care is delivered - enabling faster response and pandemic preparedness3.

HealthPulse AI algorithms

HealthPulse AI provides a library of AI algorithms for the top RDTs for malaria, HIV, and COVID. Each algorithm is a collection of Computer Vision (CV) models that are trained using machine learning (ML) algorithms. From an image of an RDT, our algorithms can:

  • Flag image quality issues common on low-end phones (blurriness, over/underexposure)
  • Detect the RDT type
  • Interpret the test result

Image Quality Assurance

When capturing an image of an RDT, it is important to ensure that the image captured is human and AI interpretable to power the use cases described above. Image quality issues are common, particularly when images are captured with low-end phones in settings that may have poor lighting or simply captured by users with shaky hands. As such, HealthPulse AI provides image quality assurance (IQA) to identify adversarial image conditions. IQA returns concerns detected and can be used to request users to retake the photo in real time. Without IQA, clients would have to retest due to uninterpretable images and expired RDT read windows in telehealth use cases, for example. With just-in-time quality concern flagging, additional cost and treatment delays can be avoided. Examples of some adversarial images that IQA would flag are shown in Figure 1 below.

Images of malaria, HIV and COVID tests that are dark, blurry, too bright, and too small.
Figure 1: Images of malaria, HIV and COVID tests that are dark, blurry, too bright, and too small.


With just an image captured on a 5MP camera from low-end smartphones commonly used in Africa, SE Asia, and Latin America where a disproportionate disease burden exists, HealthPulse AI can identify a specific test (brand, disease), individual test lines, and provide an interpretation of the test. Our current library of AI algorithms supports many of the most commonly used RDTs for malaria, HIV, and COVID-19 that are W.H.O. pre-qualified. Our AI is condition agnostic and can be easily extended to support any RDT for a range of communicable and non-communicable diseases (Diabetes, Influenza, Tuberculosis, Pregnancy, STIs and more).

HealthPulse AI is able to detect the type of RDT in the image (for supported RDTs that the model was trained for), detect the presence of lines, and return a classification for the particular test (e.g. positive, negative, invalid, uninterpretable). See Figure 2.

Figure 2: Interpretation of a supported lateral flow rapid test.
Figure 2: Interpretation of a supported lateral flow rapid test.

How and why we use MediaPipe

Deploying HealthPulse AI in decentralized care settings with unstable infrastructure comes with a number of challenges. The first challenge is a lack of reliable internet connectivity, often requiring our CV and ML algorithms to run locally. Secondly, phones available in these settings are often very old, lacking the latest hardware (< 1 GB of ram and comparable CPU specs), and on different platforms and versions ( iOS, Android, Huawei; very old versions - possibly no longer receiving OS updates) mobile platforms. This necessitates having a platform agnostic, highly efficient inference engine. MediaPipe’s out-of-the-box multi-platform support for image-focused machine learning processes makes it efficient to meet these needs.

As a non-profit operating in cost-recovery mode, it was important that solutions:

  • have broad reach globally,
  • are low-lift to maintain, and
  • meet the needs of our target population for offline, low resource, performant use.

Without needing to write a lot of glue code, HealthPulse AI can support Android, iOS, and cloud devices using the same library built on MediaPipe.

Our pipeline

MediaPipe’s graph definitions allow us to build and iterate our inference pipeline on the fly. After a user submits a picture, the pipeline determines the RDT type, and attempts to classify the test result by passing the detected result-window crop of the RDT image to our classifier.

For good human and AI interpretability, it is important to have good quality images. However, input images to the pipeline have a high level of variability we have little to no control over. Variability factors include (but are not limited to) varying image quality due to a range of smartphone camera features/megapixels/physical defects, decentralized testing settings which include differing and non-ideal lighting conditions, random orientations of the RDT cassettes, blurry and unfocused images, partial RDT images, and many other adversarial conditions that add challenges for the AI. As such, an important part of our solution is image quality assurance. Each image passes through a number of calculators geared towards highlighting quality concerns that may prevent the detector or classifier from doing its job accurately. The pipeline elevates these concerns to the host application, so an end-user can be requested in real-time to retake a photo when necessary. Since RDT results have a limited validity time (e.g. a time window specified by the RDT manufacturer for how long after processing a result can be accurately read), IQA is essential to ensure timely care and save costs. A high level flowchart of the pipeline is shown below in Figure 3.

Figure 3: HealthPulse AI pipeline
Figure 3: HealthPulse AI pipeline


HealthPulse AI is designed to improve the quality and richness of testing programs and data in underserved communities that are disproportionately impacted by preventable communicable and non-communicable diseases.

Towards this mission, MediaPipe plays a critical role by providing a platform that allows Audere to quickly iterate and support new rapid diagnostic tests. This is imperative as new rapid tests come to market regularly, and test availability for community and home use can change frequently. Additionally, the flexibility allows for lower overhead in maintaining the pipeline, which is crucial for cost-effective operations. This, in turn, reduces the cost of use for governments and organizations globally that provide services to people who need them most.

HealthPulse AI offerings allow organizations and governments to benefit from new innovations in the diagnostics space with minimal overhead. This is an essential component of the primary health journey - to ensure that populations in under-resourced communities have access to timely, cost-effective, and efficacious care.

About Audere

Audere is a global digital health nonprofit developing AI based solutions to address important problems in health delivery by providing innovative, scalable, interconnected tools to advance health equity in underserved communities worldwide. We operate at the unique intersection of global health and high tech, creating advanced, accessible software that revolutionizes the detection, prevention, and treatment of diseases — such as malaria, COVID-19, and HIV. Our diverse team of passionate, innovative minds combines human-centered design, smartphone technology, artificial intelligence (AI), open standards, and the best of cloud-based services to empower innovators globally to deliver healthcare in new ways in low-and-middle income settings. Audere operates primarily in Africa with projects in Nigeria, Kenya, Côte d’Ivoire, Benin, Uganda, Zambia, South Africa, and Ethiopia.

1 WHO malaria fact sheets

NordVPN boosted the speed of its login user flow by 60% using Baseline Profiles

Posted by Ben Weiss, Senior Developer Relations Engineer

NordVPN is a virtual private network (VPN) app that protects users while they’re browsing the web by providing them a more secure and private connection. As a network utility, NordVPN’s users deserve a responsive UI, allowing them to set up their protections at a moment’s notice. That's why NordVPN developers recently integrated Baseline Profiles, a profile-guided optimization that helps Android developers improve an app's startup and runtime performance using ahead-of-time compilation.

Improving performance with Baseline profiles

As part of its product roadmap for 2023, the NordVPN team wanted to boost the application’s performance. Before implementing Baseline Profiles, NordVPN’s startup times on Android devices didn’t meet the team’s standards, prompting them to examine new ways to make the app run better.

After exploring ways to improve its runtime performance and streamline the login process for users, NordVPN developers identified an opportunity to make the app faster using Baseline Profiles. Baseline Profiles lets the Android Runtime (ART) know which code paths to optimize through Ahead-of-Time (AOT) compilation before an app launches, boosting speed, stability, and overall responsiveness during startup, when navigating through the app, and while viewing content.

“App speed and stability are essential for a better user experience, so we’re always looking for new ways to improve NordVPN’s performance,” said Himanshu Singh, senior Android engineer at NordVPN. “We wanted to speed up the app’s load time and make launch and navigation faster than ever.”

By applying Baseline Profiles, NordVPN improved its launch speed by an average of 24%. Using tools like Android Vitals, the NordVPN team measured that it had reduced the application’s cold start time from 4.3 seconds to 3.2 seconds, the warm start time from 2.7 seconds to 1.8 seconds, and the hot start time from 1 second to 0.7 seconds.

After implementation, NordVPN developers' also noticed that Baseline Profiles made it faster for users to login to the app, improving the user login flow. The login flow is measured from when a user starts an app to when a user is logged into it. Using the Macrobenchmark library to monitor the improvements, the team observed that the NordVPN app runs its login flow 60% faster than before.

A black quote card featuring a headshot if Ernestas on the right with text in white that reads “The introduction of Baseline Profiles helped us achieve outstanding results, elevating our application’s speed with minimal effort.” — Ernestas Balčiūnas, engineering lead at NordVPN

Integrating and testing Baseline Profiles is easy

The ease of implementing Baseline Profiles impressed NordVPN developers. The available resources, in-depth documentation, and codelabs from Android allowed them to enhance the app’s UX without having to write an extensive amount of code themselves.

Using the Macrobenchmark library, NordVPN developers quickly generated Baseline Profiles for the application. To do this, they used a Gradle managed device, which enabled them to create new profiles without a physical device. Using a Gradle Managed Device also allowed NordVPN developers to create fresh profiles for each app release build on their Continuous Integration platform. Looking forward, NordVPN developers plan to migrate Baseline Profile generation to the official Gradle plugin, which will further automate profile generation.

NordVPN developers combined development workflows to create an integration pipeline, allowing them to test the app under various conditions. Then, the Macrobenchmark library ran Baseline generation tests, pushing the latest Baseline Profiles into the code base.

A black Quote card featuring droid on the right side and a green half oval overlay on the left with white text that reads, 'Applying Baseline Profiles in the NordVPN application led to a 29% improvement to overall in-app speed.'

A quick boost to app quality

After integrating Baseline Profiles into NordVPN’s code, its developers saw immediate speed improvements. The engineering team assessed the app’s overall speed after finishing the project and found that, beyond improving the app’s launch times, applying Baseline Profiles led to a 29% improvement to overall in-app speed.

"We’re constantly working to improve app quality, and Baseline Profiles integration has proven to be one of the most successful steps we’ve taken,” said Šarūnas Rimša, product owner at NordVPN. “We’re helping users access the services they’re entitled to faster. What's not to like?"

Get started

Learn how you can improve your app’s performance using Baseline Profiles.

Snapchat integrated new camera features 50% faster with the Camera2 Extensions API

Posted by Fred Chung, Android Developer Relations

Snapchat is a visual messaging app that enhances Snapchatters’ relationships with friends, family, and the world. It opens to the camera and offers millions of augmented reality and AI-powered Lenses for self expression, learning, and play. Ensuring Snapchatters can easily capture and share their lives with close friends and family is a priority for Snapchat, and they're always exploring new ways to improve the overall app experience.

As part of this, the Snapchat team added new camera features into the app using Android’s Camera2 Extensions API, which allows developers to access various capabilities that OEMs have implemented on various devices, like Night Mode and Bokeh. Thanks to Android’s intuitive API, the Snapchat team implemented new camera features 50% faster than before.

Camera2 Extensions API gives access to advanced features

The Snapchat team wanted to optimize the application for the expanding selection of Android devices, knowing many OEMs differentiate their devices with their respective camera technologies. As Snapchat is a primarily visual app that works with a device’s camera, the team optimizes the app to take full advantage of each device’s unique hardware.

“We wanted to leverage each OEM’s software to enhance the Snapchat experience on Android,” said Ye Tian, a software engineer at Snapchat. “This would help the app achieve higher-quality Snaps that are comparable to what a device's native camera offers.”

Snapchat developers enhanced the app’s zoom and night mode camera capabilities using the Camera2 Extensions API

What started as a goal to improve the app’s low-light capabilities led to much more. The Snapchat team worked on finding new ways to improve the app’s camera capabilities by implementing features like night mode, portrait mode, face retouch, tap-to-focus, zoom, and more.

“Our collaboration with Google Pixel paved the way for collaboration with other OEMs to implement night mode and super-night mode in their devices with very minimal code changes,” said Ye. “The Camera2 Extensions API is flexible and extensive. Snapchat can now use it to build full-fledged applications on demand without negatively impacting performance and stability.”

The implementation via the Camera2 Extension API made it easy for Snapchat developers to add more camera features into the app. And using the extensions made available with Android’s camera API, Snapchat integrated new camera features 50% faster when compared to the typical industry-standard approaches it used in the past.

The Camera2 Extensions API is flexible and extensive. Snapchat can now use it to build full-fledged applications on demand without negatively impacting performance and stability.” — Ye Tian, Software Engineer at Snapchat

More opportunities on more devices

The Snapchat team was happy to give its users a more cohesive experience using the Camera2 Extensions API. Thanks to the extensions provided in the API, developers easily improved the app’s camera on a range of manufacturer devices using the Android platform, and much faster than before.

“I enjoy the diversity of the Android platform and utilizing the unique advantages of each mobile phone manufacturers’ devices,” said Ye. “It helps us bring their cutting-edge innovations into the Snapchat app, allowing Snapchatters to better capture their life moments.”

Snapchat’s team looks forward to working with more OEMs to further improve the app’s processing capabilities across devices using the Camera2 Extensions API. They’re also looking forward to improving the app’s backward compatibility using the new API, which will allow even more users to benefit from the extensions.

“I would recommend using Camera2 Extension API. It provides extensive functionalities and stable performance to improve the velocity that developers can deliver features,” said Ye.

Get started

Learn how to increase your app’s camera capabilities with the Camera2 Extensions API.

Meta built threads in only 5 months using Jetpack Compose

Posted by Yasmine Evjen – Product Manager, and Florina Muntenescu – Developer Relations Engineer

Following its release in July of 2023, Meta’s Threads became the most rapidly downloaded app ever with over 100 million downloads in its first week. Meta created the new text-based social media platform as a place to build connections and have meaningful conversations. To ensure the app was set up for success at its release and into the future, Threads developers used Jetpack Compose, Android’s modern declarative toolkit for building UI.

An easier way to build UI with Jetpack Compose

Threads is built on top of existing code from its sister app Instagram, which uses Views for its UI development. After positive reports from other Android developers about Compose, and following internal testing and an assessment of the toolkit’s benefits, Threads engineers opted to build the all-new app from scratch using Compose. By using Compose, the team could move faster and better prepare the app for any future updates.

“We decided Jetpack Compose would be our target UI framework going forward,” said Richard Zadorozny, a software engineer at Threads. “We wanted to build the new app UI from scratch using Compose because it would enable us to move faster than refactoring a large application like Instagram.”

Even though most of Threads’ engineers had no prior experience using Compose, they found it easy to get started and learn the new toolkit. With Compose, Threads engineers built and shipped the app in only five months. This greatly exceeded the team’s speed expectations for developing a high-quality Android application — especially of this complexity and scale. The team attributes much of this speed to the flexibility and decoupling Compose provided.

Compose helped Threads engineers streamline the development of new product features. The modular nature of the toolkit let Threads developers iterate on the app as it evolved and teed up the app’s architecture for future development. Compose also helped engineers build user-friendly features that adhered to Material Design guidelines.

Threads was built and shipped in five months, exceeding our speed expectations for building a high-quality Android app of this complexity and scale.”  — Richard Zadorozny, software engineer at Threads

Going all in with Compose

Threads engineers developed almost all of the app’s surfaces using Compose. In the end, they built over 90% of Threads using Compose, including the app’s activity feed, navigation, search, profiles, onboarding page, shared element transitions, media viewer, settings, and more.

While Compose did mostly everything Threads engineers needed it to, it was still easy for them to interoperate with Views as necessary. They used Views for Threads’ videos and the media picker that’s available when creating a new post.

Compose provides modern APIs that ship directly with an app. Because of this, Threads engineers spent less time worrying about backward compatibility, missing features, or differing functionality between different versions of Android. Instead, they could focus their energy on developing a high-quality application.

“Compose’s design encourages a modular, plug-in approach to development,” said Richard. “Modifiers make all sorts of functionality inherently reusable, so you no longer have to subclass complicated ViewGroups or lump all sorts of logic into one place.”

Moving image shows Jetpack Compose/Modifiers code appears on screen

The Threads team used Modifiers for the app’s custom click behaviors and its thread line illustration that appears on the left side of posts. Modifiers also allowed Threads developers to easily add the app’s branding to any elements and ensured they were properly aligned on-screen.

Threads engineers also ensured the app was ready for users across platforms at launch. That meant making sure Threads resizes to work on different devices, like large screens and foldables. The adaptive layouts Compose offers ensure an app responds properly to different screen sizes, orientations, and form factors. This made it easier for the Threads app to “just work” for configuration changes, according to Richard.

For developers who are building new apps, I would definitely recommend using Compose. Not only is it enjoyable… it sets your team up for success in the future.” — Richard Zadorozny, software engineer at Threads

Compose is the ‘future’ of Android UI

Compose offered Threads developers an easier way to design and create UI while preparing the app’s architecture for the future. With its intuitive composables and modern declarative framework, Compose made end-to-end development smooth and gave Threads developers confidence that updating the app would be easy.

Given the positive results the team saw with the release of Threads, Meta plans to expand its use of Compose to some of Instagram’s most important surfaces, like the app’s main feed.

“It’s reached a point where Jetpack Compose can do almost everything you’ll need, and its modular nature makes it easy to make most of the changes you would need to fill the gaps,” said Richard. “I believe Compose is the future of Android UI development, and it’s just fun!”

Get started

Optimize your UI development with Jetpack Compose.

How KAYAK reduced sign in time by 50% and improved security with passkeys

Posted by Kateryna Semenova, Developer Relations Engineer, Android


KAYAK is one of the world's leading travel search engines that helps users find the best deals on flights, hotels, and rental cars. In 2023, KAYAK integrated passkeys - a new type of passwordless authentication - into its Android and web apps. As a result, KAYAK reduced the average time it takes their users to sign-up and sign-in by 50%, and also saw a decrease in support tickets.

This case study explains KAYAK's implementation on Android with Credential Manager API and RxJava. You can use this case study as a model for implementing Credential Manager to improve security and user experience in your own apps.

If you want a quick summary, check out the companion video on YouTube.


Like most businesses, KAYAK has relied on passwords in the past to authenticate users. Passwords are a liability for both users and businesses alike: they're often weak, reused, guessed, phished, leaked, or hacked.

“Offering password authentication comes with a lot of effort and risk for the business. Attackers are constantly trying to brute force accounts while not all users understand the need for strong passwords. However, even strong passwords are not fully secure and can still be phished.” – Matthias Keller, Chief Scientist and SVP, Technology at KAYAK

To make authentication more secure, KAYAK sent "magic links" via email. While helpful from a security standpoint, this extra step introduced more user friction by requiring users to switch to a different app to complete the login process. Additional measures needed to be introduced to mitigate the risk of phishing attacks.


KAYAK's Android app now uses passkeys for a more secure, user-friendly, and faster authentication experience. Passkeys are unique, secure tokens that are stored on the user's device and can be synchronized across multiple devices. Users can sign in to KAYAK with a passkey by simply using their existing device's screen lock, making it simpler and more secure than entering a password.

“We've added passkeys support to our Android app so that more users can use passkeys instead of passwords. Within that work, we also replaced our old Smartlock API implementation with the Sign in with Google supported by Credential Manager API. Now, users are able to sign up and sign in to KAYAK with passkeys twice as fast as with an email link, which also improves the completion rate" – Matthias Keller, Chief Scientist and SVP, Technology at KAYAK

Credential Manager API integration

To integrate passkeys on Android, KAYAK used the Credential Manager API. Credential Manager is a Jetpack library that unifies passkey support starting with Android 9 (API level 28) and support for traditional sign-in methods such as passwords and federated authentication into a single user interface and API.

Image of Credential Manager's passkey creation screen.
Figure 1: Credential Manager's passkey creation screens.

Designing a robust authentication flow for apps is crucial to ensure security and a trustworthy user experience. The following diagram demonstrates how KAYAK integrated passkeys into their registration and authentication flows:

Flow diagram of KAYAK's registration and authentication processes
Figure 2:KAYAK's diagram showing their registration and authentication flows.

At registration time, users are given the opportunity to create a passkey. Once registered, users can sign in using their passkey, Sign in with Google, or password. Since Credential Manager launches the UI automatically, be careful not to introduce unexpected wait times, such as network calls. Always fetch a one-time challenge and other passkeys configuration (such as RP ID) at the beginning of any app session.

While the KAYAK team is now heavily invested in coroutines, their initial integration used RxJava to integrate with the Credential Manager API. They wrapped Credential Manager calls into RxJava as follows:

override fun createCredential(request: CreateCredentialRequest, activity: Activity): Single<CreateCredentialResponse> { return Single.create { emitter -> // Triggers credential creation flow credentialManager.createCredentialAsync( request = request, activity = activity, cancellationSignal = null, executor = Executors.newSingleThreadExecutor(), callback = object : CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException> { override fun onResult(result: CreateCredentialResponse) { emitter.onSuccess(result) } override fun onError(e: CreateCredentialException) { emitter.tryOnError(e) } } ) } }

This example defines a Kotlin function called createCredential() that returns a credential from the user as an RxJava Single of type CreateCredentialResponse. The createCredential() function encapsulates the asynchronous process of credential registration in a reactive programming style using the RxJava Single class.

For a Kotlin implementation of this process using coroutines, read the Sign in your user with Credential Manager guide.

New user registration sign-up flow

This example demonstrates the approach KAYAK used to register a new credential, here Credential Manager was wrapped in Rx primitives.

webAuthnRetrofitService .getClientParams(username = /** email address **/) .flatMap { response -> // Produce a passkeys request from client params that include a one-time challenge CreatePublicKeyCredentialOption(/** produce JSON from response **/) } .subscribeOn(schedulers.io()) .flatMap { request -> // Call the earlier defined wrapper which calls the Credential Manager UI // to register a new passkey credential credentialManagerRepository .createCredential( request = request, activity = activity ) } .flatMap { // send credential to the authentication server } .observeOn(schedulers.main()) .subscribe( { /** process successful login, update UI etc. **/ }, { /** process error, send to logger **/ } )

Rx allowed KAYAK to produce more complex pipelines that can involve multiple interactions with Credential Manager.

Existing user sign-in

KAYAK used the following steps to launch the sign-in flow. The process launches a bottom sheet UI element, allowing the user to log in using a Google ID and an existing passkey or saved password.

Image of bottom sheet for passkey authentication
Figure 3:Bottom sheet for passkey authentication.

Developers should follow these steps when setting up a sign-in flow:

  1. Since the bottom sheet is launched automatically, be careful not to introduce unexpected wait times in the UI, such as network calls. Always fetch a one-time challenge and other passkeys configuration (such as RP ID) at the beginning of any app session.
  2. When offering Google sign-in via Credential Manager API, your code should initially look for Google accounts that have already been used with the app. To handle this, call the API with the setFilterByAuthorizedAccounts parameter set to true.
  3. If the result returns a list of available credentials, the app shows the bottom sheet authentication UI to the user.
  4. If a NoCredentialException appears, no credentials were found: No Google accounts, no passkeys, and no saved passwords. At this point, your app should call the API again and set setFilterByAuthorizedAccounts to false to initiate the Sign up with Google flow.
  5. Process the credential returned from Credential Manager.
Single.fromSupplier<GetPublicKeyCredentialOption> { GetPublicKeyCredentialOption(/** Insert challenge and RP ID that was fetched earlier **/) } .flatMap { response -> // Produce a passkeys request GetPublicKeyCredentialOption(response.toGetPublicKeyCredentialOptionRequest()) } .subscribeOn(schedulers.io()) .map { publicKeyCredentialOption -> // Merge passkeys request together with other desired options, // such as Google sign-in and saved passwords. } .flatMap { request -> // Trigger Credential Manager system UI credentialManagerRepository.getCredential( request = request, activity = activity ) } .onErrorResumeNext { throwable -> // When offering Google sign-in, it is recommended to first only look for Google accounts // that have already been used with our app. If there are no such Google accounts, no passkeys, // and no saved passwords, we try looking for any Google sign-in one more time. if (throwable is NoCredentialException) { return@onErrorResumeNext credentialManagerRepository.getCredential( request = GetCredentialRequest(/* Google ID with filterByAuthorizedOnly = false */), activity = activity ) } Single.error(throwable) } .flatMapCompletable { // Step 1: Use Retrofit service to send the credential to the server for validation. Waiting // for the server is handled on a IO thread using subscribeOn(schedulers.io()). // Step 2: Show the result in the UI. This includes changes such as loading the profile // picture, updating to the personalized greeting, making member-only areas active, // hiding the sign-in dialog, etc. The activities of step 2 are executed on the main thread. } .observeOn(schedulers.main()) .subscribe( // Handle errors, e.g. send to log ingestion service. // A subset of exceptions shown to the user can also be helpful, // such as user setup problems. // Check out more info in Troubleshoot common errors at // https://developer.android.com/training/sign-in/passkeys#troubleshoot )

“Once the Credential Manager API is generally implemented, it is very easy to add other authentication methods. Adding Google One-Tap Sign In was almost zero work after adding passkeys.” – Matthias Keller

To learn more, follow the guide on how to Integrate Credentials Manager API and how to Integrate Credential Manager with Sign in with Google.

UX considerations

Some of the major user experience considerations KAYAK faced when switching to passkeys included whether users should be able to delete passkeys or create more than one passkey.

Our UX guide for passkeys recommends that you have an option to revoke a passkey, and that you ensure that the user does not create duplicate passkeys for the same username in the same password manager.

Image of KAYAK's UI for passkey management
Figure 4:KAYAK's UI for passkey management.

To prevent registration of multiple credentials for the same account, KAYAK used the excludeCredentials property that lists credentials already registered for the user. The following example demonstrates how to create new credentials on Android without creating duplicates:

fun WebAuthnClientParamsResponse.toCreateCredentialRequest(): String { val credentialRequest = WebAuthnCreateCredentialRequest( challenge = this.challenge!!.asSafeBase64, relayingParty = this.relayingParty!!, pubKeyCredParams = this.pubKeyCredParams!!, userEntity = WebAuthnUserEntity( id = this.userEntity!!.id.asSafeBase64, name = this.userEntity.name, displayName = this.userEntity.displayName ), authenticatorSelection = WebAuthnAuthenticatorSelection( authenticatorAttachment = "platform", residentKey = "preferred" ), // Setting already existing credentials here prevents // creating multiple passkeys on the same keychain/password manager excludeCredentials = this.allowedCredentials!!.map { it.copy(id = it.id.asSafeBase64) }, ) return GsonBuilder().disableHtmlEscaping().create().toJson(credentialRequest) }

And this is how KAYAK implemented excludeCredentials functionality for their Web implementation.

var registrationOptions = { 'publicKey': { 'challenge': self.base64ToArrayBuffer(data.challenge), 'rp': data.rp, 'user': { 'id': new TextEncoder().encode(data.user.id), 'name': data.user.name, 'displayName': data.user.displayName }, 'pubKeyCredParams': data.pubKeyCredParams, 'authenticatorSelection': { 'residentKey': 'required' } } }; if (data.allowCredentials && data.allowCredentials.length > 0) { var excludeCredentials = []; for (var i = 0; i < data.allowCredentials.length; i++) { excludeCredentials.push({ 'id': self.base64ToArrayBuffer(data.allowCredentials[i].id), 'type': data.allowCredentials[i].type }); } registrationOptions.publicKey.excludeCredentials = excludeCredentials; } navigator.credentials.create(registrationOptions);

Server-side implementation

The server-side part is an essential component of an authentication solution. KAYAK added passkey capabilities to their existing authentication backend by utilizing WebAuthn4J, an open source Java library.

KAYAK broke down the server-side process into the following steps:

  1. The client requests parameters needed to create or use a passkey from the server. This includes the challenge, the supported encryption algorithm, the relying party ID, and related items. If the client already has a user email address, the parameters will include the user object for registration, and a list of passkeys if any exist.
  2. The client runs browser or app flows to start passkey registration or sign-in.
  3. The client sends retrieved credential information to the server. This includes client ID, authenticator data, client data, and other related items. This information is needed to create an account or verify a sign-in.

When KAYAK worked on this project, no third-party products supported passkeys. However, many resources are now available for creating a passkey server, including documentation and library examples.


Since integrating passkeys, KAYAK has seen a significant increase in user satisfaction. Users have reported that they find passkeys to be much easier to use than passwords, as they do not require users to remember or type in a long, complex string of characters. KAYAK reduced the average time it takes their users to sign-up and sign-in by 50%, have seen a decrease in support tickets related to forgotten passwords, and have made their system more secure by reducing their exposure to password-based attacks. Thanks to these improvements, ​​KAYAK plans to eliminate password-based authentication in their app by the end of 2023.

“Passkeys make creating an account lightning fast by removing the need for password creation or navigating to a separate app to get a link or code. As a bonus, implementing the new Credential Manager library also reduced technical debt in our code base by putting passkeys, passwords and Google sign-in all into one new modern UI. Indeed, users are able to sign up and sign in to KAYAK with passkeys twice as fast as with an email link, which also improves the completion rate." – Matthias Keller


Passkeys are a new and innovative authentication solution that offers significant benefits over traditional passwords. KAYAK is a great example of how an organization can improve the security and usability of its authentication process by integrating passkeys. If you are looking for a more secure and user-friendly authentication experience, we encourage you to consider using passkeys with Android's Credential Manager API.

Password manager Dashlane sees 70% increase in conversion rate for signing-in with passkeys compared to passwords

Posted by Milica Mihajlija, Technical Writer

This article was originally posted on Google for Developers

Dashlane is a password management tool that provides a secure way to manage user credentials, access control, and authentication across multiple systems and applications. Dashlane has over 18 million users and 20,000 businesses in 180 countries. It’s available on Android, iOS, macOS, Windows, and as a web app with an extension for Chrome, Firefox, Edge, and Safari.

The opportunity

Many users choose password managers because of the pain and frustration of dealing with passwords. While password managers help here, the fact remains that one of the biggest issues with passwords are security breaches. Passkeys on the other hand bring passwordless authentication with major advancements in security.

Passkeys are a simple and secure authentication technology that enables signing in to online accounts without entering a password. They cannot be reused, don't leak in server breaches of relying parties, and protect users from phishing attacks. Passkeys are built on open standards and work on all major platforms and browsers.

As an authentication tool, Dashlane’s primary goal is to ensure customers’ credentials are kept safe. They realized how significant the impact of passkeys could be to the security of their users and adapted their applications to support passkeys across devices, browsers, and platforms. With passkey support they provide users a secure and convenient access with a phishing-resistant authentication method.


Passkeys as a replacement for passwords is a relatively new concept and to address the challenge of going from a familiar to an unfamiliar way of logging in, the Dashlane team considered various solutions.

On the desktop web they implemented conditional UI support through a browser extension to help users gracefully navigate the choice between using a password and a passkey to log into websites that support both login methods. As soon as the user taps on the username input field, an autofill suggestion dialog pops up with the stored passkeys and password autofill suggestions. The user can then choose an account and use the device screen lock to sign in.

Moving image showing continual UI experience on the web

Note: To learn how to add passkeys support with conditional UI to your web app check out Create a passkey for passwordless logins and Sign in with a passkey through form autofill.

On Android, they used the Credential Manager API which supports multiple sign-in methods, such as username and password, passkeys, and federated sign-in solutions (such as Sign-in with Google) in a single API. The Credential Manager simplifies the development process and it has enabled Dashlane to implement passkeys support on Android in 8 weeks with a team of one engineer.

Moving image showing authentication UI experience in android

Note: If you are a credential provider, such as a password manager app, check out the guide on how to integrate Credential Manager with your credential provider solution.


Data shows that users are more satisfied with the passkey flows than the existing password flows.

The conversion rate is 92% on passkey authentication opportunities on the web (when Dashlane suggests a saved passkey for the user to sign in), compared to a 54% conversion rate on opportunities to automatically sign in with passwords. That’s a 70% increase in conversion rate compared to passwords–a great sign for passkey adoption.

Graph showing evolution of positive actions on passkeys, measuring the rates of authentication with a passkey and registration of a passkey over a six month period

Image showing password sign-in prompt
Password sign-in prompt.

Image showing passkey sign-in prompt
Passkey sign-in prompt.

The conversion rate here refers to user actions when they visit websites that support passkeys. If a user attempts to register or use a passkey they will see a Dashlane dialog appear on Chrome on desktop. If they proceed and create new or use an existing passkey it is considered a success. If they dismiss the dialog or cancel passkey creation, it’s considered a failure. The same user experience flow applies to passwords.

Dashlane also saw a 63% conversion rate on passkey registration opportunities (when Dashlane offers to save a newly created passkey to the user’s vault) compared to only around 25% conversion rate on suggestions to save new passwords. This indicates that Dashlane’s suggestions to save passkeys are more relevant and precise than the suggestions to save passwords.

Image showing save passkey prompt
Save passkey prompt.

Image showing save password prompt
Save password prompt.

Dashlane observed an acceleration of passkey usage with 6.8% average weekly growth of passkeys saved and used on the web.

graph showing % of Active users that performed a passkey related event, out of users having ever interacted with a passkey with a moving average on 7 days over a six month period
Save password prompt.


While passkeys are a new technology that users are just starting to get familiar with, the adoption rate and positive engagement rates show that Dashlane users are more satisfied with passkey flows than the existing password flows. 

“Staying up to date on developments in the market landscape and industry, anticipating the potential impact to your customers’ experience, and being ready to meet their needs can pay off. Thanks in part to our rapid implementation of the Credential Manager API, customers can rest assured that they can continue to rely on Dashlane to store and help them access services, no matter how authentication methods evolve.“ –Rew Islam, Director of Product Engineering and Innovation at Dashlane

Dashlane tracks and investigates all passkey errors and says that there haven’t been many. They also receive few questions from customers around how to use or manage their passkeys. This can be a sign of an intuitive user experience, clear help center documentation, a tendency of passkey users today already being knowledgeable about passkeys, or some combination of these factors.