Recommendations
The ContactsManager SDK provides intelligent recommendation features to enhance your app’s social experience. These recommendations help users discover connections in different contexts, like finding users already using your app or suggesting people they might know.
Types of Recommendations
The SDK offers several recommendation types:
Contacts to Invite : Identify contacts who would benefit from using your app
App Users : Find contacts who are already using your app
People You Might Know : Discover potential connections based on shared contacts
Get a list of contacts that would be good to invite to your app:
Swift
Kotlin
Objective-C
React Native
do {
let recommendations = try await ContactsService . shared
. getSharedContactsByUsersToInvite ( limit: 10 )
for recommendation in recommendations {
let contact = recommendation. contact
let score = recommendation. score
let reason = recommendation. reason
print ( " \( contact. displayName ?? "Unknown" ) - Score: \( score ) - " +
"Reason: \( reason ) " )
}
} catch {
print ( "Error getting invitation recommendations: \( error. localizedDescription ) " )
}
Recommendation Scores
Each recommendation includes a score between 0.0 and 1.0 that indicates how relevant the recommendation is. Higher scores indicate stronger recommendations.
App Users
Find contacts who are already using your app:
Swift
Kotlin
Objective-C
React Native
do {
let appUsers = try await ContactsService . shared. getContactsUsingApp ( limit: 20 )
print ( "Found \( appUsers. count ) contacts using the app" )
for appUser in appUsers {
let contact = appUser. contact
let organizationUserId = appUser. canonicalContact. organizationUserId
print ( " \( contact? . displayName ?? "Unknown" ) - " +
"User ID: \( organizationUserId ) " )
}
} catch {
print ( "Error getting app users: \( error. localizedDescription ) " )
}
Using Organization User IDs
The organizationUserId
property allows you to connect the local contact with their server-side identity, which is useful for social features.
People You Might Know
Discover potential connections based on mutual contact information:
Swift
Kotlin
Objective-C
React Native
do {
let connections = try await ContactsService . shared. getUsersYouMightKnow ( limit: 15 )
print ( "Found \( connections. count ) people you might know" )
for user in connections {
print ( " \( user. fullName ) - " +
" \( user. email ?? user. phone ?? "No contact info" ) " )
}
} catch {
print ( "Error getting connection recommendations: \( error. localizedDescription ) " )
}
Building a Recommendation UI
Here’s an example of how to build a recommendations UI using SwiftUI:
Swift
Kotlin
Objective-C
React Native
struct RecommendationsView : View {
@State private var inviteRecommendations: [ ContactRecommendation ] = [ ]
@State private var appUsers: [ LocalCanonicalContact ] = [ ]
@State private var peopleYouMightKnow: [ CanonicalContact ] = [ ]
@State private var isLoading = true
@State private var error: Error ?
var body: some View {
ScrollView {
if isLoading {
ProgressView ( "Loading recommendations..." )
. padding ( )
} else if let error = error {
VStack {
Text ( "Error loading recommendations" )
. font ( . headline)
Text ( error. localizedDescription)
. foregroundColor ( . red)
Button ( "Try Again" ) {
loadRecommendations ( )
}
. padding ( )
}
} else {
VStack ( alignment: . leading, spacing: 20 ) {
if ! appUsers. isEmpty {
Text ( "People you know using the app" )
. font ( . headline)
. padding ( . horizontal)
ScrollView ( . horizontal, showsIndicators: false ) {
HStack ( spacing: 12 ) {
ForEach ( appUsers, id: \ . canonicalContact. id) { user in
AppUserCard ( user: user)
}
}
. padding ( . horizontal)
}
}
if ! peopleYouMightKnow. isEmpty {
Text ( "People you might know" )
. font ( . headline)
. padding ( . horizontal)
ScrollView ( . horizontal, showsIndicators: false ) {
HStack ( spacing: 12 ) {
ForEach ( peopleYouMightKnow, id: \ . id) { user in
PeopleYouMightKnowCard ( user: user)
}
}
. padding ( . horizontal)
}
}
if ! inviteRecommendations. isEmpty {
Text ( "Invite to the app" )
. font ( . headline)
. padding ( . horizontal)
ScrollView ( . horizontal, showsIndicators: false ) {
HStack ( spacing: 12 ) {
ForEach ( inviteRecommendations, id: \ . contact. id) {
recommendation in
InviteRecommendationCard (
recommendation: recommendation
)
}
}
. padding ( . horizontal)
}
}
}
}
}
. navigationTitle ( "Recommendations" )
. onAppear {
loadRecommendations ( )
}
}
private func loadRecommendations ( ) {
isLoading = true
error = nil
Task {
do {
async let inviteTask = ContactsService . shared
. getSharedContactsByUsersToInvite ( limit: 10 )
async let appUsersTask = ContactsService . shared
. getContactsUsingApp ( limit: 10 )
async let peopleTask = ContactsService . shared
. getUsersYouMightKnow ( limit: 10 )
let ( invite, users, people) = try await (
inviteTask,
appUsersTask,
peopleTask
)
await MainActor . run {
self . inviteRecommendations = invite
self . appUsers = users
self . peopleYouMightKnow = people
self . isLoading = false
}
} catch {
await MainActor . run {
self . error = error
self . isLoading = false
}
}
}
}
}
struct AppUserCard : View {
let user: LocalCanonicalContact
var body: some View {
VStack {
if let contact = user. contact,
let imageData = contact. thumbnailImageData,
let uiImage = UIImage ( data: imageData) {
Image ( uiImage: uiImage)
. resizable ( )
. scaledToFill ( )
. frame ( width: 80 , height: 80 )
. clipShape ( Circle ( ) )
} else {
Circle ( )
. fill ( Color . gray. opacity ( 0.3 ) )
. frame ( width: 80 , height: 80 )
. overlay (
Text ( user. contact? . initials ?? "?" )
. font ( . title2)
)
}
Text ( user. contact? . displayName ?? user. canonicalContact. fullName)
. font ( . subheadline)
. fontWeight ( . medium)
. lineLimit ( 1 )
Button ( "Follow" ) {
}
. padding ( . horizontal, 16 )
. padding ( . vertical, 6 )
. background ( Color . blue)
. foregroundColor ( . white)
. cornerRadius ( 12 )
. font ( . caption)
}
. frame ( width: 100 )
. padding ( . vertical)
}
}
Best Practices
Load Recommendations Asynchronously : Use async/await to load recommendations without blocking the UI
Implement Pagination : For large contact lists, use the limit
parameter to paginate results
Handle Permission Changes : Reload recommendations when contact permissions change
Cache Results Temporarily : Avoid excessive API calls by caching results for a short period
Show Loading States : Always show appropriate loading indicators during network operations
Troubleshooting
Common Issues
Empty Recommendations
Ensure the user has granted contacts access
Verify that contacts have been synced with syncContacts()
Check if the user has enough contacts for meaningful recommendations
Missing User Information
Make sure contacts have proper phone numbers or email addresses
Ensure the server has up-to-date user information
Poor Recommendation Quality
Increase the contacts sync frequency
Encourage users to complete their profiles
Consider implementing a feedback mechanism for recommendations