Plaid Link for iOS


Overview

Introduction

Here you find instructions on how to integrate and use Plaid Link for iOS. At the center of it lies LinkKit.framework : an embeddable framework managing the details of linking an account with Plaid.

To get up and running quickly with Plaid Link for iOS clone the GitHub repository and try out the example applications, which provide a reference implementation in Swift and Objective-C. Youʼll want to sign up for free API keys to get started.

Examples of Plaid Link for iOS

Requirements

A new version of LinkKit.framework will be released around the 15th of every month and we highly recommend you keep up to date to provide the best Plaid Link experience in your application.

Plaid Link for iOS Quickstart

  1. Integrate the LinkKit.framework into your application using CocoaPods, Carthage, or manually
  2. Add a custom Run Script build phase containing this script to run after the Embed Frameworks build phase. This prepares LinkKit.framework for distribution through the App Store.

Failing to do so will very likely get your application rejected during App Store submission or review!

  1. Import LinkKit
  2. Adopt the PLKPlaidLinkViewDelegate protocol
  3. Implement the delegate methods
  4. Create a link_token from your server
  5. Present the PLKPlaidLinkViewController

Integration


Plaid Link for iOS is an embedabble framework that is bundled and distributed within your application. There are several ways to obtain the necessary files and keep them up-to-date, we recommend using CocoaPods or Carthage. Regardless of what you choose, submitting a new version of your application with the updated LinkKit.framework to the App Store is required.

CocoaPods

To integrate LinkKit.framework using CocoaPods


pod install
  • Add a custom Run Script build phase (we recommend naming it Prepare for Distribution ) with the script below, which prepares the LinkKit.framework for distribution through the App Store.

    Failing to do so will very likely get your application rejected during App Store submission or review!

  • To update to newer releases in the future run the following command


pod update Plaid

Carthage

To integrate LinkKit.framework using Carthage

  • Add binary "https://raw.githubusercontent.com/plaid/plaid-link-ios/master/LinkKit.json" to your project's Cartfile

  • Run the following command to download the latest version of LinkKit.framework


carthage update
  • Follow the manual instructions below

Manual

Get the latest version of LinkKit.framework and embed it into your application. If you chose to integrate using Carthage and have followed the steps above LinkKit.framework has already been downloaded to Carthage/Build/iOS/LinkKit.framework.

Embed LinkKit.framework into your application, for example by dragging and dropping the file onto the Embed Frameworks build phase as shown below.

Embed LinkKit.framework

Depending on the location of the LinkKit.framework on the filesystem you may need to change the Framework Search Paths build setting to avoid the error: fatal error: 'LinkKit/LinkKit.h' file not found, see image below.

The LinkDemo Xcode projects have it set to FRAMEWORK_SEARCH_PATHS = $(PROJECT_DIR)/../ for example, since the LinkKit.framework file is shared between them and is kept in the directory that also contains the demo project directories.

Edit framework search paths build setting

Finally, add a Run Script build phase (we recommend naming it Prepare for Distribution ) with the script below. Be sure to run this build phase after the Embed Frameworks build phase (or [CP] Embed Pods Frameworks build phase when integrating using CocoaPods), otherwise LinkKit.framework will not be properly prepared for distribution.

Failing to do so will very likely get your application rejected during App Store submission or review!

Add Run Script Build PhaseEdit Run Script Build Phase

The script below removes any non-iOS device code from the framework which is included to support running LinkKit in the Simulator but may not be distributed via the App Store.

Failing to do so will very likely get your application rejected during App Store submission or review!

Change the ${PROJECT_DIR}/LinkKit.framework path in the example below according to your setup, and be sure to quote the filepaths when they contain whitespace.

Run Script

  LINK_ROOT=${PODS_ROOT:+$PODS_ROOT/Plaid/ios}
  cp "${LINK_ROOT:-$PROJECT_DIR}"/LinkKit.framework/prepare_for_distribution.sh "${CODESIGNING_FOLDER_PATH}"/Frameworks/LinkKit.framework/prepare_for_distribution.sh
  "${CODESIGNING_FOLDER_PATH}"/Frameworks/LinkKit.framework/prepare_for_distribution.sh
  

Configuration

To enable support for third-party password managers in Plaid Link for iOS add org-appextension-feature-password-management to the LSApplicationQueriesSchemes array in the applicationʼs Info.plist (see LinkDemo example and the Information Property List Key Reference ).

The way to configure Plaid Link for iOS is by creating a custom instance of PLKConfiguration and passing it to the PLKPlaidLinkViewController.

Available API environments
  • sandbox: Stateful sandbox environment; use test credentials and build out and test your integration
  • development: Test your integration with live credentials; you will need to request access before you can use our Development environment
  • production: Production API environment; all requests are billed

Optional items

ItemDescription
oauthStateId
String
An oauthStateId is required to support OAuth authentication flows when re-launching Link using one or more European country codes.
oauthRedirectUri
String
An oauthRedirectUri is required to support OAuth authentication flows when launching Link and using one or more European country codes.
oauthNonce
String
An oauthNonce is required to support OAuth authentication flows when launching or re-launching Link and using one or more European country codes.

Deprecated items

The following configuration items have been deprecated and will be removed in a future release.

ItemDescription
selectAccount
Boolean
Whether the user should select a specific account after successfully linking their bank account (default: NO ).
Note: Use the Select Account view from the Dashboard to control whether or not your Link integration uses the Select Account view

Implementation

Plaid Link for iOS presents itself through the PLKPlaidLinkViewController class.

The steps to implement Plaid Link for iOS in your application are:

  1. Import LinkKit
  2. Adopt the PLKPlaidLinkViewDelegate protocol
  3. Implement the delegate methods
  4. Present the PLKPlaidLinkViewController

Import LinkKit

To use Plaid Link for iOS import LinkKit and its symbols into your code.


import LinkKit

#import <LinkKit/LinkKit.h>

Adopt the PLKPlaidLinkViewDelegate protocol

In the LinkDemo applications this is handled by the main view controller object.


extension ViewController : PLKPlaidLinkViewDelegate

@interface ViewController (PLKPlaidLinkViewDelegate) <PLKPlaidLinkViewDelegate>
@end

Implement the delegate methods

The PLKPlaidLinkViewDelegate methods are the main communication back channel to your application for Plaid Link for iOS.

onSuccess

This delegate method is called when the user successfully linked their bank account with Plaid. Use this to upload and store the publicToken with your service for use with the Plaid API.

onSuccess

func linkViewController(_ linkViewController: PLKPlaidLinkViewController, didSucceedWithPublicToken publicToken: String, metadata: [String : Any]?) {
    dismiss(animated: true) {
        // Handle success, e.g. by storing publicToken with your service
        NSLog("Successfully linked account!\npublicToken: (publicToken)\nmetadata: (metadata ?? [:])")
        self.handleSuccessWithToken(publicToken, metadata: metadata)
    }
}
          

- (void)linkViewController:(PLKPlaidLinkViewController<em>)linkViewController
 didSucceedWithPublicToken:(NSString</em>)publicToken
                  metadata:(NSDictionary<NSString<em>,id></em> _Nullable)metadata {
    [self dismissViewControllerAnimated:YES completion:^{
        // Handle success, e.g. by storing publicToken with your service
        NSLog(@"Successfully linked account!\npublicToken: %@\nmetadata: %@", publicToken, metadata);
        [self handleSuccessWithToken:publicToken metadata:metadata];
    }];
}
          

onExit

This delegate method is called when the user exited from Plaid Link or when an error occurred. In case of an error you may want to display error related information to user and have them retry linking their account.

onExit

func linkViewController(_ linkViewController: PLKPlaidLinkViewController, didExitWithError error: Error?, metadata: [String : Any]?) {
    dismiss(animated: true) {
        if let error = error {
            NSLog("Failed to link account due to: (error.localizedDescription)\nmetadata: (metadata ?? [:])")
            self.handleError(error, metadata: metadata)
        }
        else {
            NSLog("Plaid link exited with metadata: (metadata ?? [:])")
            self.handleExitWithMetadata(metadata)
        }
    }
}

          

- (void)linkViewController:(PLKPlaidLinkViewController<em>)linkViewController
          didExitWithError:(NSError</em> _Nullable)error
                  metadata:(NSDictionary<NSString<em>,id></em> _Nullable)metadata {
    [self dismissViewControllerAnimated:YES completion:^{
        if (error) {
            NSLog(@"Failed to link account due to: %@\nmetadata: %@", [error localizedDescription], metadata);
            [self handleError:error metadata:metadata];
        }
        else {
            NSLog(@"Plaid link exited with metadata: %@", metadata);
            [self handleExitWithMetadata:metadata];
        }
    }];
}
          

onEvent

This optional delegate method is called when certain events in the Plaid Link flow have occurred, for example when the user selected an instutition. This enables your application to gain further insight into what is going on as the user goes through the Plaid Link flow. For details about the events see the link-web onEvent documentation.

onEvent

func linkViewController(_ linkViewController: PLKPlaidLinkViewController, didHandleEvent event: String, metadata: [String : Any]?) {
    NSLog("Link event: (event)\nmetadata: (metadata ?? [:])")
}
          

- (void)linkViewController:(PLKPlaidLinkViewController<em>)linkViewController
            didHandleEvent:(NSString</em>)event
                  metadata:(NSDictionary<NSString<em>,id></em> _Nullable)metadata {
    NSLog(@"Link event: %@\nmetadata: %@", event, metadata);
}
          

The metadata contains the following keys, note that values can be [NSNull null].

ConstantDescription
kPLKMetadataAccountIdKey
String
Identifier for the selected account
kPLKMetadataAccountKey
Dictionary
Contains the keys kPLKMetadataIdKey, kPLKMetadataNameKey, kPLKMetadataTypeKey, kPLKMetadataSubtypeKey, and kPLKMetadataMaskKey. Only applicable when the selectAccount property is set to true
kPLKMetadataAccountsKey
Dictionary
Contains the keys kPLKMetadataIdKey, kPLKMetadataNameKey, kPLKMetadataTypeKey, kPLKMetadataSubtypeKey, and kPLKMetadataMaskKey. Only applicable when the selectAccount property is set to true
kPLKMetadataIdKey
String
Identifier for the selected account
kPLKMetadataNameKey
String
Name of the institution or selected account
kPLKMetadataTypeKey
String
Type of the institution or selected account
kPLKMetadataSubtypeKey
String
Subtype of the selected account
kPLKMetadataMaskKey
String
Mask of the selected account
kPLKMetadataInstitutionKey
Dictionary
Contains the keys kPLKMetadataNameKey and kPLKMetadataInstitutionTypeKey
kPLKMetadataStatusKey
String
Indicates the point at which the user exited the Link flow (see explanation of possible values ).
kPLKMetadataRequestIdKey
String
An internal identifier that helps us track your request in our system, please include it in every support request
kPLKMetadataPlaidApiRequestIdKey
String
An internal identifier that helps us track your request in our system, please include it in every support request
kPLKAPIv1MetadataInstitutionTypeKey
String
Identifier for the institution reported in the event callback metadata when using the legacy API
kPLKMetadataInstitution_TypeKey
String
Deprecated in favor of kPLKAPIv1MetadataInstitutionTypeKey
kPLKMetadataInstitutionTypeKey
String
Deprecated in favor of kPLKMetadataTypeKey

In addition to the above the metadata contains the following keys for onEvent delegate method, note that values can be [NSNull null].

ConstantDescription
kPLKMetadataInstitutionSearchQueryKey
String
The query used to search for institutions.
kPLKMetadataInstitutionIdKey
String
The ID of the selected institution.
kPLKMetadataInstitutionNameKey
String
The name of the selected institution.
kPLKMetadataLinkRequestIdKey
String
The request ID for the last request made by Link. This can be shared with Plaid Support to expedite investigation.
kPLKMetadataLinkSessionIdKey
String
The link_session_id is a unique identifier for a single session of Link. It is always available and will stay constant throughout the flow.
kPLKMetadataErrorTypeKey
String
The error type that the user encountered.
kPLKMetadataErrorCodeKey
String
The error code that the user encountered.
kPLKMetadataErrorMessageKey
String
The error message that the user encountered.
kPLKMetadataMFATypeKey
String
If set, the user has encountered one of the following MFA types: code, device, questions, selections.
kPLKMetadataViewNameKey
String
The name of the view that is being transitioned to.
kPLKMetadataTimestampKey
String
An ISO 8601 representation of when the event occurred.
kPLKMetadataExitStatusKey
String
The status key indicates the point at which the user exited the Link flow.

Possible values for the kPLKMetadataStatusKey metadata:

ConstantDescription
kPLKStatusConnected User completed the Link flow
kPLKStatusRequiresQuestions User prompted to answer security question(s)
kPLKStatusRequiresSelections User prompted to answer multiple choice question(s)
kPLKStatusRequiresCode User prompted to provide a one-time passcode.
kPLKStatusChooseDevice User prompted to select a device at which to receive a one-time passcode.
kPLKStatusRequiresCredentials User prompted to provide credentials for the selected financial institution or has not yet selected a financial institution
kPLKStatusRequiresRecaptcha User prompted to verify they are human via reCAPTCHA
kPLKStatusInstitutionNotFound User exited the Link flow after unsuccessfully (no results returned) searching for a financial institution

Presentation

Presenting PLKPlaidLinkViewController

Starting the Plaid Link for iOS experience is as simple as creating a new link_token and using it to initialize PLKConfiguration and PLKPlaidLinkViewController.

To create an instance of PLKConfiguration, use initWithLinkToken: where the only parameter is your generated link_token. You can then instantiate PLKPlaidLinkViewController with initWithLinkToken:configuration:delegate: where you will pass in your link_token, PLKConfiguration object, and delegate that you just created. The only step left is to present your PLKPlaidLinkViewController.

Present PLKPlaidLinkViewController with link_token and configuration

// With custom configuration
let linkConfiguration = PLKConfiguration(linkToken: "<GENERATED_LINK_TOKEN>")
let linkViewDeletgate = self
let linkViewController = PLKPlaidLinkViewController(
  linkToken: "<GENERATED_LINK_TOKEN>",
  configuration: linkConfiguration,
  delegate: linkViewDelegate)

if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}

present(linkViewController, animated: true)

// With custom configuration
PLKConfiguration<em> linkConfiguration;
@try {
    linkConfiguration = [[PLKConfiguration alloc] initWithLinkToken:@"<GENERATED_LINK_TOKEN>"];
    id<PLKPlaidLinkViewDelegate> linkViewDelegate  = self;
    PLKPlaidLinkViewController* linkViewController =
      [[PLKPlaidLinkViewController alloc] initWithLinkToken:@"<GENERATED_LINK_TOKEN>"
                                              configuration:linkConfiguration
                                                   delegate:linkViewDelegate];
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        linkViewController.modalPresentationStyle = UIModalPresentationFormSheet;
    }
    [self presentViewController:linkViewController animated:YES completion:nil];
} @catch (NSException *exception) {
    NSLog(@"Invalid configuration: %@", exception);
}
          

If your integration is still using a public_key to initialize Link, view our migration guide to upgrade to link_tokens. You can also view our maintenance guide to troubleshoot any public_key issues.

Update mode

Initializing Link iOS in update mode is no different than initializing Link iOS normally. The only difference is that you are using a link_token that is specifically configured for update mode.

Learn more about how to create a link_token for update mode.

OAuth Support

To support OAuth, you will need to create an instance of PLKConfiguration and set oauthRedirectUri and oauthNonce on the configuration when initially launching Link.

Your oauthRedirectUri must be configured through Plaid's developer dashboard and should be configured as a universal link using an Apple App Association File. For more details about this, see the Allowed redirect URIs section on our main documentation page.

For security, the oauthNonce must be uniquely generated for each login and at least 16 characters in length. We suggest using a UUID.

Initialize Link with oauthNonce and oauthRedirectUri

// With custom configuration
let linkConfiguration = PLKConfiguration(linkToken: "<GENERATED_LINK_TOKEN>")
linkConfiguration.oauthRedirectUri = "<YOUR_OAUTH_REDIRECT_URI>"
let oauthNonce = UUID().uuidString
linkConfiguration.oauthNonce = oauthNonce
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(
  linkToken: "<GENERATED_LINK_TOKEN>"
  configuration: linkConfiguration,
  delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
PLKConfiguration<em> linkConfiguration;
@try {
    linkConfiguration = [[PLKConfiguration alloc] initWithLinkToken:@"<GENERATED_LINK_TOKEN>"];
    linkConfiguration.oauthRedirectUri = @"<YOUR_OAUTH_REDIRECT_URI>";
    NSString* oauthNonce = [[NSUUID UUID] UUIDString];
    linkConfiguration.oauthNonce = oauthNonce;
    id<PLKPlaidLinkViewDelegate> linkViewDelegate  = self;
    PLKPlaidLinkViewController</em> linkViewController =
      [[PLKPlaidLinkViewController alloc] initWithLinkToken:@"<GENERATED_LINK_TOKEN>"
                                              configuration:linkConfiguration
                                                   delegate:linkViewDelegate];
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        linkViewController.modalPresentationStyle = UIModalPresentationFormSheet;
    }
    [self presentViewController:linkViewController animated:YES completion:nil];
} @catch (NSException *exception) {
    NSLog(@"Invalid configuration: %@", exception);
}
          

When re-initializing Link to complete the authentication flow, the oauthNonce from the original Link initialization must be passed into the PLKConfiguration and the returned oauthStateId must be used to initialize the PLKPlaidLinkViewController. You should use PLKOAuthStateIdFromURL to get the correct oauthStateId to use.

Re-initialize Link with oauthNonce and oauthStateId

// With custom configuration
let oauthStateId = PLKOAuthStateIdFromURL(url: "<YOUR_OAUTH_RESPONSE_URL>")
let linkConfiguration = PLKConfiguration(linkToken: "<GENERATED_LINK_TOKEN>")
linkConfiguration.oauthNonce = "<YOUR_OAUTH_NONCE>"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(
  linkToken: "<GENERATED_LINK_TOKEN>"
  oauthStateId: oauthStateId
  configuration: linkConfiguration
  delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
PLKConfiguration<em> linkConfiguration;
@try {
    NSString* oauthStateId = PLKOAuthStateIdFromURL(@"<YOUR_OAUTH_RESPONSE_URL>")];
    linkConfiguration = [[PLKConfiguration alloc] initWithLinkToken:@"<GENERATED_LINK_TOKEN>"];
    linkConfiguration.oauthNonce = @"<YOUR_OAUTH_NONCE>";
    id<PLKPlaidLinkViewDelegate> linkViewDelegate  = self;
    PLKPlaidLinkViewController<em> linkViewController =
      [[PLKPlaidLinkViewController alloc] initWithLinkToken:@"<GENERATED_LINK_TOKEN>"
                                               oAuthStateId:oauthStateId
                                              configuration:linkConfiguration
                                                   delegate:linkViewDelegate];
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        linkViewController.modalPresentationStyle = UIModalPresentationFormSheet;
    }
    [self presentViewController:linkViewController animated:YES completion:nil];
} @catch (NSException </em>exception) {
    NSLog(@"Invalid configuration: %@", exception);
}
          

For more details about this full flow and requirements around these additional fields, please visit the OAuth authentication flows section on our main documentation page.

Customization

The preferred and recommended method to customize LinkKit is to use customization feature in the dashboard, Plaid Link for iOS will automatically use the values you provide there.

Troubleshooting

When things work differently as expected LinkKit will use the value of the PLKPLAIDLINK_DIAGNOSTICS environment variable and enable different logging to the console. Supported values for PLKPLAIDLINK_DIAGNOSTICS and their corresponding log level are:

ValueLoglevel
0 None
1 Error
2 Warning
3 Info
4 Debug

Environment Variables can be added in the Arguments tab of the Run phase in the Scheme Editor (Product ► Scheme ► Edit Scheme ⌘< ).

Edit SchemaTroubleshooting

Moving Forward

Migrating to production

Keep building your integration out in our Sandbox and Development API environments. When youʼre ready to go to Production, request access from the Dashboard. While you’re at it, be sure to also take a look at our Privacy Policy.

Getting help

Find answers to common integration and product questions at our Help Center. You can find all the code for this guide, including runnable sample applications, on GitHub.

Weʼre excited to see what you build!