As various teams at Yelp were focused on developing features to help businesses adapt to COVID-19, some teams were looking ahead and developing features that would help businesses in the later stages or after the pandemic.

The Challenge

Early on in the pandemic, we saw some businesses pause advertising on Yelp as government regulations required many businesses temporarily close or limit their operations. However, businesses quickly adjusted to the local regulations, while implementing health and safety precautions to keep their staff and customers safe. Through this adjustment we wanted to ensure it was easy to restart advertising right where they left off.

Our data revealed that as of April 2017, most business owners used password-based logins to sign into their business owner account. However, if they forgot their password, it could be a frustrating experience for them to continue into the app.

A typical Reset Password flow looked like:

After receiving their Reset Password link, they were presented with

Depending on what the users entered into the two input boxes, they could receive the following error messages:

  • Please enter a password
  • Oops, the passwords you entered don’t match!
  • Please choose a password of at least 6 characters
  • This password is insecure, please try a different one.
  • This password has been used in the past year. Please enter a different password.
  • … and more…

Our data showed that we sent one of these errors about 7,500 times a day.

Our Approach

To resolve this, our solution was to remove the need to authenticate a business owner with a password by creating a passwordless login. Yelp will send a unique link (called Magic Links) which are short-lived (ie. 1-hour to up to 3 days) links that provide automatic login functionality. A Magic Link will automatically open the Yelp for Business app, verify a business owner’s credentials, log them in, and then optionally redirect them to anywhere in the app of our choosing. Magic Links are one-time use and time sensitive, so the links will eventually expire if they aren’t used.

To unlock the full capabilities of this feature, we also appended each Magic Link with a redirect link that takes them to a specific page after automatic successful login. The redirect link can consist of any deeplink that we already currently support. Particularly for this initiative, we redirected our users to our One Click Restart screen, which allowed business owners to restart their ads with Yelp.

We have implemented this logic on Android, iOS, and the web. Even if business owners did not have the Yelp for Businesses app installed on their device, they can still take advantage of this feature.

Cool! But how is this magical?

With this solution, we are able to provide a seamless user journey for business owners to the end goal, securely and with only one click. Technically, it was a creative and innovative solution.

Figure 1 shows the original status quo before we implemented Magic Links and Figure 2 shows the sequence of steps after implementing Magic Links.

At Yelp, UrlCatcherActivities are Activities that are responsible for handling deeplinks. We have deeplinks that are preceded with http://biz.yelp.com or yelp-biz://. Given two deeplinks that are exactly the same with the exception of the host, the app could reroute them differently. Since Magic Links could be sent via device notifications or emails, we needed to support both URI hosts.

The MagicLinkUrlCatcherActivity was responsible for intercepting all Magic Links via the Android Manifest and acting on it. It validated the Magic Link and provided feedback for both successful and unsuccessful validations.

Our Magic Link schemas looked like this: https://biz.yelp.com/login/passwordless/?return_url=https://biz.yelp.com/ads/i2kK8NtpmtuKf84NYm0d3A/

An invalid Magic Link could consist of an expired, malformed, or missing MAGICLINKTOKEN.

On successful validation, we logged the user into the app. The return_url is an optional parameter. If it is present and also a valid deeplink that we supported, we then forwarded the redirect url embedded in the Magic Link to downstream UrlCatchersActivities. From that point on, the app behaved as status quo. If the return_url was not specified, we redirected to the home screen.

On unsuccessful validation, the activity is responsible for redirecting the user to the Log In screen so that users may try to enter in their credentials manually. If successful, we redirected the user to the embedded link within the Magic Link.

When the project first began, we had (naively) thought that this project would be simple (refer to Figure 1). Our initial strategy was to write the Magic Link logic in both the UrlCatcherActivities, but like most projects, the more we worked on it the more we realized that there were a lot of edge cases we had to handle. Accounting for each edge case for each UrlCatcherActivity would duplicate code and double our blast radius. On top of that, each requirement change, no matter the size, would have to be duplicated. We quickly realized that we should refactor all the code into one place sooner rather than later.

The Magic Link high level logic (illustrated by diagram below) was refactored into the MagicLinkUrlCatcherActivity.

We did not change any existing downstream logic

Each UrlCatcherActivity already contained business logic that required some time to understand. By moving all Magic Link related logic into the MagicLinkUrlCatcherActivity, we only passed the optional redirect url into the downstream logic.

We isolated our testing to the MagicLinkUrlCatcherActivity alone

We didn’t need to test this end-to-end. We only had to concentrate on 4 main areas:

Input validation

We validated that all deeplinks into the app were successfully triaged by the AndroidManifest to either go to one of the downstream UrlCatcherActivities or the MagicLinkUrlCatcherActivity

We tested that the MagicLinkUrlCatcherActivity was able to handle successful and unsuccessful validation of the Magic Link.

Lastly, we wrote tests to ensure that the embedded redirect links within the Magic Link would get passed to the correct downstream UrlCatcherActivities. Also verify when there were no redirect links passed.

Analytics

We verified that the correct analytics were fired at specific points in the code so that Yelp can track usage and other metrics of interest.

Using Magic Links together with deeplinks reduced friction for our business owners to log into their accounts and resume advertising.. By making passwords obsolete on login we reduced user churn resulting from abandoned password resets. We hope this feature will help our business owners get the word out about their business and better communicate and engage with their customers.

Acknowledgements

Shoutout goes to Karlo Pagtakhan and Khushboo Puneet for working on this with me! Also, thank you to Blake Larkin, Eric Hernandez, Rajan Roy, Joshua Walstrom, Patrick Fitzgerald, and Mark Brady for technical review and editing.

Become an Android Engineer at Yelp!

We're working on cool interesting problems everyday! Come join our Android team!

View Job

Back to blog