Invite Friends (Beta)

Note

Beta indicates an experimental feature. Breaking changes may happen with each release until this is no longer in Beta.

Digits Invite Friends feature helps apps grow their users. Your app users can invite friends from their address book to join the app. Currently we support two different modes of this feature:

  • Easy mode: We provide a drop in invitation flow for your app’s users. Digits will automatically track the invite status along all stages of this mode.
  • Advanced mode: We provide a data-only layer that returns contact entries with Digits server side information so that you can use the data to build your own custom invitation interface.

Easy Mode

Triggering the Invite Flow

In easy mode, we provide the invite interface that looks like the following.

../_images/invite_view_ui.png

Clicking on the Invite button on any contact brings up the SMS Composer ViewController from iOS with prefilled text and selected contact as the recipient. Note: you can customize the text message by setting the prefillTextBlock parameter in DGTInviteFlowConfiguration‘s initializers (See code example below). Once an invite has been sent to a contact, that contact entry will update to show the “Invited” button instead of “Invite” button to provide feedback to your users. Users can click on the “Invited” button to resend the invitation.

To trigger the UI, the app needs to call an instance method startInvitationFlowWithPresenterViewController from class DGTInvites. There are a few parameters to that method to allow you specify some configurations to fine-tune some UI displays and behavior in the whole flow. You can refer to the header files for detailed info. Here are some code examples:

// Objective-C
DGTInvites *digitsInvites = [[DGTInvites alloc] init];

DGTSMSTextBlock textBlock = ^NSString *(DGTAddressBookContact *contact, NSString *inviteUrl) {
    if (invitedUrl) {
        return [NSString stringWithFormat:@"Check out this cool app at %@", inviteUrl];
    } else {
        return @"Check out this awsome app!";
    }
};

DGTInviteFlowConfiguration *configuration = [[DGTInviteFlowConfiguration alloc]
                                                    initWithAppDisplayName:nil
                                                         withViewTitleText:@"SampleApp Invites"
                                        withBranchIntegrationConfiguration:nil
                                                      withPrefillTextBlock:textBlock];

[digitsInvites startInvitationFlowWithPresenterViewController:self
                                            withConfiguration:configuration
                                 withUserActionNotifyDelegate:self
                                           withFlowCompletion:nil];
// Swift
let digitsInvites = DGTInvites()
let prefillTextBlock: (DGTAddressBookContact, String?) -> String = { (contact, url) in
    if let url = url {
        return "Check out this cool app at \(url)"
    } else {
        return "Check out this awesome app!"
    }
}

let inviteFlowConfiguration = DGTInviteFlowConfiguration(appDisplayName: nil, withViewTitleText: "SampleApp Invites",
    withBranchIntegrationConfiguration: nil, withPrefillTextBlock: textGenerator)

digitsInvites.startInvitationFlowWithPresenterViewController(self, withConfiguration: inviteFlowConfiguration,
    withUserActionNotifyDelegate: self, withFlowCompletion: nil)

Sending invites in easy mode works in both the logged-in case (invite senders sign into digits and maintain a valid digits session) and the logged-out case (invite senders do not have an active digits session).

Note

For logged-in user case, Digits would be able to track invitations on server side, but we only keep it for 30 days and they will expire after that. For logged-out user case, Digits would only remember the invited state in the current invitation flow session. If the user exits the view and then re-enters, Digits will not be able to know that an invitation was previously sent by that user.

Notifications about Converted Users on Sign-in and Sign-up

When a user receives an invite and then joins by signing into the app via Digits, Digits can notify the app if it registers a delegate (conforming to protcol DGTAttributionEventDelegate) with Digits’s attributionEventDelegate property. In particular, the delegate method inviteConversionDetectedWithMatches will be called. This notification is only available for those invitations sent by users who are logged-in.

Answers Events when using Easy Mode

If your app also has Answers installed, throughout the entire invitation flow, the following Answers events will be generated to help app track metrics around users’ invite activities.

  • Digits-Invite-Sent : This event is created when an app user sends out a SMS message from the SMS Composer interface which is launched by clicking “Invite” or “Invited” button from the invite view.
  • Digits-Invite-Recipient-First-Launched-App : This is created when an invited user installs and launched your app via a Branch link they received. It’s only available when the app initializes Branch session using nitSessionWithDigits as illustrated in Branch session initialization example.
  • Digits-Invite-Converted : This is created when invited user signs into Digits while the server is able to match pending invites to that user based on the target phone numbers used in invites. Since we only track pending invites on server side for logged-in users, this Answer event is only available when invites are sent by a logged-in user. If there are multiple pending invitations to a specific phone number, then a single ‘Digits-Invite-Converted’ event will be sent for each and all of these pending invites will be turned into converted state on Digits server side.

Theming when using Easy Mode

The UI view displayed in easy mode will be subject to the theming settings as mentioned in Theming. When you use easy mode without users signing into Digits, consult the Theming Without Login Flow section on how to apply the theming.

Advanced Mode

In Advanced Mode, your app can create any UI that you desire. Digits will read the user’s local address book entries and then combine the information on our servers to provide information back to your app. There are two possible approaches for using the advanced mode, DGTContactsFetcher and DGTContactsInvitationDataSource. DGTContactsFetcher contains a single method that allows you to fetch a list of contacts with pending/invitable/in-app states, which is encapsulted in an object called DGTAddressBookContact. DGTContactsInvitationDataSource is a class that conforms to the UITableViewDataSource protocol and is intended to simpify your view controller logic when creating a custom invitation flow.

Fetching Contacts using DGTContactsFetcher

To get an instance of DGTContactsFetcher, you need to call [[Digits sharedInstance] createContactsFetcher] and in the view controller’s viewDidLoad (or where you made the request to fetch the contacts), the method fetchContactsOnlyInApp. The following sample code shows how the contacts fetcher can be used:

// Objective-C
[self.dataSource fetchContactsOnlyInApp:NO
                         withCompletion:^
 (NSArray<DGTAddressBookContact *> * _Nullable contacts, NSError * _Nullable error) {
     if (error) {
         NSLog(@"error: %@", error.localizedDescription);
         return;
     }

     [weakSelf.tableView reloadData];
}];
// Swift
self.dataSource.fetchContactsOnlyInApp(false) { [weak self] (contacts, error) in
  if let error = error {
       print("Error: ", error)
       return
  }

  self?.tableView.reloadData()
}

Note

DGTContactsFetcher does not rely on a user to be logged-in in order to fetch contacts. If the user is logged-out, the returned array of contacts will have the invited property set to false.

Creating a Custom Invitation Flow using DGTContactsInvitationDataSource

DGTContactsInvitationDataSource relies on the table view cell to be a subclass of DGTConfigurableTableViewCell, which is a simple subclass of UITableViewCell with required configure: method that must be implemented. The following code snippets are sections of a view controller that take advantage of the DGTContactsInvitationDataSource.

// Objective-C
- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
    self.dataSource = [[DGTContactsInvitationDataSource alloc] init];
    self.dataSource.delegate = self;
    self.dataSource.tableView = self.tableView;
    self.dataSource.cellClass = [DGTContactsListTableViewCell class];
    self.tableView.delegate = self;
    self.tableView.dataSource = self.dataSource;
    [self.view addSubview:self.tableView];

    __block __weak MyViewController *weakSelf = self;
    [self.dataSource fetchContactsOnlyInApp:NO
                             withCompletion:^
     (NSArray<DGTAddressBookContact *> * _Nullable contacts, NSError * _Nullable error) {
         if (error) {
             NSLog(@"error: %@", error.localizedDescription);
             return;
         }

         [weakSelf.tableView reloadData];
    }];
}
// Swift
override func viewDidLoad() {
  super.viewDidLoad()
  self.tableView = UITableView(frame: self.view.frame, style:.plain)
  self.dataSource = DGTContactsInvitationDataSource()
  self.dataSource.delegate = self
  self.dataSource.tableView = self.tableView
  self.datasource.cellClass = DGTContactsListTableViewCell.self
  self.tableView.delegate = self
  self.tableView.dataSource = self.dataSource
  self.view.addSubview(self.tableView)

  self.dataSource.fetchContactsOnlyInApp(false) { [weak self] (contacts, error) in
    if let error = error {
      print("Error: ", error)
      return
    }

    self?.tableView.reloadData()
  }
}

DGTContactsListTableViewCell is a subclass of DGTConfigurableTableViewCell that implements the configure method and lays out its’ views based on the properties of DGTAddressBookContact.

configure doesn’t allow for any communication from the cell back to the view controller (for example, you want to perform an action as a result of a button press), DGTContactsInvitationDataSourceDelegate has a method called contactsInvitationDataSource:configurableCell:forRowAtIndexPath which provides a reference to a configurable cell that can be type-casted to set a delegate. The following code snippet shows how you can set the delegate of your UITableViewCell subclass:

// Objective-C
- (void)contactsInvitationDataSource:(DGTContactsInvitationDataSource *)dataSource
                    configurableCell:(DGTConfigurableTableViewCell *)cell
                   forRowAtIndexPath:(NSIndexPath *)indexPath
{
    DGTContactsListTableViewCell *listCell = (DGTContactsListTableViewCell *)cell;
    if (listCell) {
        listCell.delegate = self;
    }
}
// Swift
func contactsInvitationDataSource(dataSource: DGTContactsInvitationDataSource, configurableCell: DGTConfigurableTableViewCell, forRowAtIndexPath:NSIndexPath) {
  if let listCell = configurableCell as? DGTContactsListTableViewCell {
    listCell.delegate = self
  }
}

Answers Events when using Advanced Mode

  • Digits-Invite-Sent: We have no control over the user interface, we are unable to track when an invite is sent on the client. This event will not be written to Answers.
  • Digits-Invite-Recipient-First-Launched-App: If you have configured Branch with :code:initSessionWithDigits, this event will automatically be sent.
  • Digits-Invite-Converted: This event will be automatically sent when a new user has successfully logged in with Digits.