Zomato brings us closer to the food we love in many different ways. It’s a one-stop-shop for finding the best pizzerias to order from, quirky cafes for perfect weekend brunches, or the newly opened brewhouses.
As our platform has evolved over the years, and we expanded our offerings even further, the search and discovery experience became more and more fragmented. A couple of months ago, our team took on a challenge of refreshing the UI/UX for our users and at the center of this effort was the unification of the search and discovery experience.
In this post (Part 1: Product Framework, Part 2: Technology Architecture), we will share our process and learnings while building a personalized flexible search and discovery experience at Zomato.
Part 1 – Product Framework
If you are a Zomato user, you must have noticed multiple search bars across our previous app. We had custom built search experiences for individual use-cases such as online ordering, Zomato Gold, etc. These search funnels allowed limited search spaces, and also had different interfaces. Not only was this confusing for our users, it required maintenance of multiple UI elements, APIs and analytics. So, it was clear to us that we needed to offer a unified experience for search, irrespective of the use-case.
To unify the search experience for the v14 app, we defined our search space as a combination of entities and intents. We offer multiple entities (such as restaurants, cuisines, dishes, attributes, collections, etc.) that you can search for with an intent (online ordering, self pickup, going out for a meal, going out for a drink) in mind. Our unified search, needs to account for relevance in this wide search space and hence requires us to guess both the ‘entity’ as well as ‘intent’.
Explicit vs Implicit Signals
When you start typing your query (explicit signal), there are multiple results that can be candidates for it. We assign a text match score to each candidate. For certain entities, like restaurants, cuisines, and dishes, we also have a popularity score, which is derived from user interest (searches, orders, page views) in these entities.
In addition to this, there are implicit signals that help us predict the intent. For example, if you are at a saved location, chances are that you might be looking to order in. Similarly, on a weekend you are more likely to go out for drinks. So, signals such as location, session activity, time of day, day of the week, as well as your search, order history, etc. are used to formulate an intent score for each search.
By combining the text score, popularity score and intent score, we assign a combined relevance score to each entity-intent result. We use this score to rank our results.
When the relevance score of one of the results crosses a defined threshold, we declare the result as the leader. In a leader state, we dismiss other result candidates and give more prominence to the results of the leader entity to bring more contextual results right on the autosuggestion page. Currently, we are able to detect leaders in about 65% of queries. This is an ongoing effort, and we hope to take this to 90% in the next few weeks so that you can search accurately and faster.
After you tap on a result of a search query, or navigate to a cuisine page, you land on a list of restaurants. For broad intents or dense neighbourhoods, there can be hundreds of restaurants in the result set. We noticed our users get indecisive if there are a lot of results for them to choose from (click through rate of broad intents is lower than that of narrower intents). So to help you “filter” your result set, we built suggested filters. By mapping related entities and collecting data on which filters get used in which context, we compiled a filter graph.
This graph currently powers our Suggested Filters rail. These filters are contextual i.e., if you search for Cafes, filters like Nearest to me, WiFi, Outdoor Seating are suggested. If you are looking for online ordering, Previously Ordered, Express Delivery filters are suggested and so on. “Suggested Filters” are also personalized i.e., your most used and recently used filters are suggested for quick access.
Personalization with a server configurable UI
Our new design system, Sushi, is a modular framework comprised of re-usable components that can be put together, lego-style, to craft any use-case as needed. We can push new UI elements to any page, without the need for an app update, akin to content on the web frameworks. This is amazingly powerful yet flexible. Across our latest app, we use this backend configurability to serve personalized, contextual search pages that can adapt and evolve with our platform. Some of the UI elements and their use-cases are shown below.
Billboards – used to set the context of a search page and to promote offers. These are digital versions of the real world billboards.
Rails – they break the monotony of a list and promote discovery within a context. You will come across restaurant, cuisine and multiple other rails through your interactions with the app.
Hero text on restaurant cards – used to surface restaurant offers, events and other contextual information.
Another core feature with this update has been end-to-end interaction tracking. Every user interaction (impression and tap) registers itself with the search_id of its parent page and when a user navigates to another page (taps on a restaurant, collection, cuisine, applies a filter, etc.), the new page registers a previous_search_id along with its own search_id. This way, by joining on previous_search_ids and new search_ids, we can quantify more than just uni-directional funnels and get a tap-by-tap understanding of user behaviour in different contexts. This is going to be central in our efforts to understand and improve the discovery experiences going forward.
Combining a server configurable UI with integrated end-to-end tracking has now empowered us to conduct insanely rapid and powerful experimentation at scale. Product development demands a lot of iterations, and now we are able to quickly rollout A/B tests and staged feature releases to validate the product’s success. At any given time, we have a number of experiments going on and this experimentation remains at the core of our product development endeavors at Zomato.
In conclusion, so far, we talked about the product framework for powering the new Search and Discovery experience at Zomato. Such a flexible UI/UX requires a comprehensive, yet lean contract with the backend. Plus, we built a dedicated service to handle all this at a massive scale.
Stay tuned for Part 2 of this post, that talks about the architecture of the new search service and how it communicates with the app.