“Frequently not having any data connection in even the wealthiest and most developed cities of the world has led us to conclude that no, the mobile connectivity/bandwidth issue isn’t just going to solve itself on a global level anywhere in the near future.”
Chop is a mobile commerce service for small and medium-sized businesses in San Francisco. Our initial focus was, and continues to be, SoMa and the Financial District. We assumed our customers in San Francisco would always have strong connectivity. That in the heart of the tech industry data connectivity would rarely be an issue. Then, during our private beta, we realized we had overlooked a very critical issue:
- Initially, we assumed Chop would be used to order ahead, or order at the store. Instead, many of our users order on the go. This results in intermittent mobile connections in an unpredictable way. While users have great connectivity in one moment, in the next they could lose connectivity while walking between two tall buildings, or entering a Bart station. We didn’t encounter this problem during internal testing, because we mostly used Chop in our offices, connected to the high speed internet.
- All of our merchants receive Chop orders on a tablet. However, some of our merchants are inside office buildings with shared WiFi. This results in a perpetually weak signal, particularly during busy hours. Meaning, user orders are delayed because of a weak signal.
Connectivity issues on both sides of the ordering process, resulted in numerous errors. We were losing orders, duplicating orders, and some were simply not going through. It was an issue we had to address before public release.
Common Use Cases for Commerce
We’re a small startup with limited resources, so we started by examining various use cases, to help us to decide what we should focus on first.
There are two user groups with common commerce use cases:
- New users who are trying to make their very first purchase
- Repeat customers
At our current stage, our key focus is to grow the number of engaged users who can complete the core actions. I recommend reading Sarah Tavel’s excellent article on The Hierarchy of Engagement.
- Browse catalog
- Add to shopping cart
- Login (for first time user)
- Setup payment (for first time user)
- Notify customer when purchase is ready
If you have 100 users at the first step, ideally you want to have 100 users at the last step. You do this by removing as much friction as possible. From the user’s perspective, the further along they are in the process, the more time and energy they’ve invested. The more invested a customer is, the angrier they’ll be if something goes wrong.
To better understand how to solve the issue of offline connectivity, I looked at similar apps to see how they were solving this problem.
Conducting offline research:
- First, I would open the app and click on all major screens. I would look through options like: browsing the catalog, past orders, adding an item to a shopping cart, or clicking on various items.
- I would then close the app, and turn my phone onto airplane mode. Then, I would open the app again and reopen all major screens. Specifically I would: browse the catalog, browse my past orders, go to the item/subcategory I visited previously, add an item to the shopping cart, got to a new item I hadn’t previously visited, and place an order.
Here’s what I discovered from my case studies:
- Amazon for iOS only provides a very basic offline check. On every page load, Amazon checks the network status and, if poor connectivity, displays a “Network Error” message while rendering the page.
- If you try to go to another page after that, it takes you to a splash page with pretty standard terminology. It is unclear what (CS1) means, it is probably an internal error code.
Amazon is the number one commerce site in the world but the offline experience is unimpressive. When operating offline, users are not given any expectations as to what should and should not work.
Starbucks delivers a similar experience. Your network status is checked on every page, and when there is poor connectivity it displays a standard error message. However, if you dismiss the message, it allows you to navigate to other cached pages before showing the same error message again.
The message dialog feels like a foreign part of the UI, cold and unintuitive, but it does get the job done — which is to confirm the network error and not to let users go any further.
Doordash, even as a younger startup, delivers a delightful experience:
- You can browse the catalog, view your order history, and even add to your shopping cart if you can access the item all the way through checkout.
- That being said, the notifications alerting users they’re offline is not always consistent. For example, if a restaurant is not available and not cached, Doordash will display a red background with no text or explanation. If you try to place an order when offline, you will see a grey system dialog or, an offline splash page. Furthermore, if you reopen the app while offline, it directs you to sign in. I don’t think that’s what they intended the user to do while they’re offline.
I researched a few more examples and found, in general, there are no established UX patterns for offline. Should users be able to browse the catalog? Should they be able to continue adding to their cart offline? How should network errors be displayed? Is it possible to design the offline experience, so users can continue even with poor connectivity?
Offline Design at Chop
Without much guidance from the more established commerce sites, we decided to follow our own design principles and be as thoughtful to the user as possible. That meant:
- Making sure the offline experience was error free for the most critical part: checkout to order completion.
- Giving users a decent browsing and shopping cart experience by caching as much data as possible. If the data is available, users can go much farther on the client side.
- Developing a generic splash page with a positive emotion, to alert users their connection is bad.
Here is what we’ve implemented so far:
In general, we leverage client’s cached data as much as possible to ensure users have a seamless offline experience. We defer checking a user’s connection until they are ready to place an order. In our case, as a mobile commerce solution only available in San Francisco, most of our users have an intermittent connection rather than no access at all. We’ve taken that into consideration. We now make several attempts to connect to a network before giving up and displaying the splash page.
We designed a splash page with a restaurant and food theme, with copy that says “Gone Fishing. Your internet is off the hook mind trying again?” It’s displayed if a user is disconnected, or if they click on a page that doesn’t have any cached data. Hopefully, it functions to lighten the mood for the user, so they are distracted from the disappointment of a failed order. At this point, we also let the user take control, and give them the option to try again.
Offline Development at Chop
While this article focuses on design, I do want to bring up a few points about development.
How to ensure there are no duplicate orders
When an order is first placed, the client generates a UUID for the order, and it is persisted to local storage on their iPhone, so if the app crashes, is killed, or otherwise needs to recover, an order in progress isn’t lost. After committing to local storage, the phone makes a REST call to the server to place the order and charge the consumer. If an existing order is already in the system and has been successfully charged with the same UUID, the order is rejected as a duplicate.
The transition to a successfully charged order is two-phased. First, the order is persisted into an ACID database marked as UNPAID, then it is read and charged to Stripe and marked PAID. If the consumer has another order in progress at the same merchant with a different UUID within a defined time window, it is also rejected, because we do not allow more than one order in progress at the same merchant by design.
The user cannot be charged for the same order twice because it is guarded by UUID check and a database check. The client also can’t submit the order twice if it has already been submitted.
How to ensure no lost orders
Our merchant tablets constantly ping heartbeats to the server. We have a Quartz Scheduler process that monitors the last time tablets have pinged the server, and how long orders at each merchant have been sitting unclaimed.
When idle time exceeds a threshold, an issue is automatically created in an internal issue tracker, and eventually escalated to Slack. If the merchant responds during this time window, the issue is automatically closed and reported to Slack as resolved.
Eventually, if the downtime persists and Slack messages do not elicit a response, it will be escalated to an SMS message.
What we have implemented so far is by no means perfect, but it is a good first step to ensure our customers can successfully make orders through intermittent connections. We are interested in delivering more. For example, on the splash page, rather than saying “Try again”, can we change it to “Notify me when online”? That way, when the phone is back online, we can send a friendly notification from which the user can preview their shopping cart and place their order without even opening the app.
Through this exercise, what I have realized is that users don’t have any set expectations for offline experiences. It is in general, as shown through my case studies, a negative spectrum. There is so little information out there about offline UX best practices, whether on web apps or native apps. There are, however, some interesting technologies available now such as Service Workers which I am hoping to explore in 2017 when we start the web app.
Through this article, I hope to see more conversations around offline design and development practices from the community, let’s make offline a positive experience.
I also found an Offline First! community which is pretty awesome.