LinkedIn Mobile Stack

Recently released LinkedIn feature on the iPhone, Android, and mobile web platforms contains a step-by-step guided flow to the LinkedIn ecosystem for our new members. This onboarding experience removes the uncertainty of how to get started and effectively use our mobile apps. It also enables our new and less active members to get the most out of the rich and diverse professional content that LinkedIn offers.

li_1

li_2

In this post, we will discuss how we built the personalized onboarding flows for the mobile app. It will briefly cover the end-end architecture of the mobile stack, how we use the LinkedIn recommendation engine and AB testing frameworks with the onboarding graph based API.

LinkedIn Mobile Stack

The LinkedIn Mobile stack consists of a frontend tier of node.js servers that provide set of APIs accessible over HTTP to the mobile clients. The LinkedIn iPhone, Android, and mobile-web clients all share this same set of APIs. The node.js tier fetches and aggregates data from one or more internal LinkedInrest.li powered services, such as the recommendation service. The mobile stack also heavily uses Voldemort, a distributed key-value store, and LiX, LinkedIn’s internal member segmenting and AB testing platform to learn and iterate on the best possible user-experience in the mobile clients

li_mobile_arch

LiX is used to decide if and how a feature should be displayed to a given user. With LiX, we can enable a feature for a specific subset of users based on a the member attributes, language, geo, date of enrollment into LinkedIn etc. It enables us to effectively roll out a feature to the entire member base controlling the segment we want to target. A LiX experiment is configured using a graphical web based user interface. For the personalized onboarding feature, LiX controls who sees the flow and what set of screens are in the flow.

li_lix

Design Goals

Building a feature on mobile often requires making tradeoffs. This post will focus on the following three general mobile design goals as they apply to building this onboarding feature on mobile.

Building a Delightful Experience

Speed plays a large part of creating a delightful mobile experience. To achieve speed, the entire onboarding process needed to be short enough so that users could quickly start using the app.

  • Fast loading initial screen
  • Fast and beautiful transitions between screens. We made heavy use of animations across all three platforms. Attention to detail matters a lot here.
  • A small number of steps in every flow and an indication of how many steps remain.

Achieving Relevance

The onboarding experience is successful only if our users gain value from completing it:

  • Member Targeting: Only new users and lowly engaged users should be shown the onboarding flow.
  • Content Type Personalization: Different types of content should be presented for different types of users. A student using LinkedIn would gain more value from following companies and jobs, while an employed professional would get more value by joining industry groups and following influencers.
  • Recommendation Personalization: For a given content type, different users should have different recommendations. For example, a software professional in the San Francisco should have much different recommendations about groups to join than a financial professional in New York City.

Creating a Flexible Design

A flexible design was essential to enable us to rapidly experiment with these three relevancy dimensions. We needed to be able to target the onboarding experience to specific sets of users, vary the order, number, and types of screens in the onboarding flow, and recommend the best items for each user for each type of content.

How We Built It

Targeting

To establish which members are eligible for the guided onboarding experience, we use LiX. Using LiX, we divide the population of members into two groups, those who should see the onboarding experience flow and those who should not based, on a recent LinkedIn join date or a low number of connections.

Once we determine that a member is eligible for the guided flow, we perform a lookup in Voldemort to determine the last time at which the member saw the guided flow. If enough time has passed since they last saw it, then we will redisplay the flow.

Personalization

Each screen is built using data from LinkedIn’s recommendation service. Content recommendations are generated via a set of Hadoop jobs running over the hundreds of millions of profiles, connections, and activities on LinkedIn. Impression and actions taken in the onboarding experience are fed back into this system to improve recommendation relevance in subsequent recommendation flows.

li_3

The set and order of screens within the flow are customized based on the demographic information provided by the member when signing up for LinkedIn. All flows begin with an optional address book import step. If the member declines the address book import option, then a different set of screens is shown.

For example, we distinguish between student and members who are employed. They would see a sequence similar to this:

  • Student: After the address book import screen, students see company and influencer recommendation screens.
  • Employee: For employed members, the guided flow will suggest groups and influencers.

Onboarding Flow Graph API
To ensure a fast initial load, quick inter-screen transitions, and to present the user with an indication of how many screens remain in the flow, we chose a directed graph data structure. The graph defines the screens, and transitions between screens, and API endpoints specifying where to get recommendation data for each screen.

Every vertex in the graph represents a single screen and contains two properties, node and edges.

node contains the information needed to fetch the recommendations and the text needed to render the screen.

Decoupled Data Fetch

Our graph does not contain the recommendations for each screen. Instead, it contains a resourcePath property that specifies another API endpoint from which the client can fetch recommendations. This decouples the graph flow control structure from the data on each screen.

Clients can prefetch data for screens before the screen is displayed without sacrificing latency on the initial load of the graph data structure itself.

The recommendation data model for each screen is independent of the type of content being recommended. This allows us to introduce a new recommendation type without updating the clients. For example, we could introduce university recommendations for students, by simply adding a new node to the graph for students.

li_4

{
"influencers": {
"node": {
"resourcePath": "/li/v2/onboard/influencers",
"logo": "influencer",
"title": "Get insights from the world's top minds",
"subtitle": "Follow LinkedIn Influencers to hear what industry leaders have to say.",
"type": "influencers",
"submitToastText": "Following",
"postResourcePath": "/li/v2/onboard/influencers"
},
"edges": {
...
}
}
}

edges enumerates all possible transitions from the current screen to other screens. edges is composed of a default object and an optional options array.

Changing the order of the screens in the flow means returning a different set of edges in the graph. Using LiX, we can experiment with screen orders for different segments of the population, again without updating the clients.

{
"influencers": {
"node": {
...
},
"edges": {
"default": {
"dest": "channels"
},
"options": [
{
"dest": null,
"predicate": [
"abi"
]
}
]
}
}
}

li_5

The default object has a dest property that specifies the identifier for the next screen. The dest property on an edge is always another named property on the graph. A dest property with the value of null means that the flow should terminate.

Each option in the options array has a dest property and an array predicate.

Predicate

The predicate array specifies one or more identifiers. The client evaluates each identifier to true or false.

If all of the identifiers in the predicate array are true, then the option evaluates to true and the client must navigate to the screen specified by dest. If the option is false, then the client must continue to evaluate the other options in the options array until exhausted. If no options evaluate to true, then the client navigates to the dest specified by default.

{
"options": [
{
"dest": null,
"predicate": [
"abi"
]
},
{
"dest": "channels",
"predicate": [
"foo"
]
},
{
"dest": "groups",
"predicate": [
"bar",
"baz"
]
}
]
}

For example, one predicate identifier we use is abi. If the user has chosen to import her address book, then abi will evaluate to true. By using this identifier in a graph vertex edges array, we can control the screen flow based on whether or not the user has performed an address book import.

This type of predicate evaluation has the following benefits:

  • Screen reordering: Can add predicates to any options array to add a new flow through the onboarding graph
  • Client screen navigation: Clients can navigate between screens without making a network call to the server since they are evaluated locally.
  • Backwards compatibility: Clients evaluates unknown predicate identifiers to false. This allows us to introduce new predicates without breaking older clients.

Root

To enter into the graph data structure, we provide a separate root node.
{
"root": {
"default": {
"dest": "pymk",
"pathLength": 4
},
"options": [{
"dest": "m2m",
"predicate": [
"abi"
],
"pathLength": 4
}]
}
}

This represents the incoming edge to the graph. It has nearly the same structure as a generic graph edge described above with the addition of pathLength, a hint to the client about how many steps there are in each possible flow originating from this edge. This value is used to display the step indicator in the UI.

li_6

Putting it all together, we arrive at the full graph structure

Conclusion

Building our APIs using a directed graph structure enables us to quickly experiment with the guided onboarding experience.

The onboarding feature has been enabled for over a month now. So far, we have observed that 76% of members complete the entire flow. Furthermore, 72% of members who complete the flow perform at least one action. On average, members who interact with a screen perform 3.7 actions on that screen.

We believe that by further tuning the ordering and types of recommendations surfaced in the onboarding experience flow, we can enable our new members to quickly get the most out of what LinkedIn has to offer.

Seen on linkedin.com.