Link iOS SDK
Reference for integrating with the Link iOS SDK
Overview
The Plaid Link SDK is a quick and secure way to link bank accounts to Plaid from within your iOS app. LinkKit is a drop-in framework that handles connecting a financial institution to your app (credential validation, multi-factor authentication, error handling, etc.) without passing sensitive information to your server.
Want even more video lessons? A full tutorial for integrating Plaid with iOS is available on our YouTube channel.
To get started with Plaid Link for iOS, clone the GitHub repository and try out the example application, which provides a reference implementation in both Swift and Objective-C. Youʼll want to sign up for free API keys through the Plaid Dashboard to get started.

Initial iOS setup
Before writing code using the SDK, you must first perform some setup steps to register your app with Plaid and configure your project.
The "Register your redirect URI" and "Set up Universal Links" steps describe setting up your app for OAuth redirects. If your integration uses only Identity Verification, Monitor, Beacon, or Document Income, they can be skipped; they are mandatory otherwise.
Register your redirect URI
- Sign in to the Plaid Dashboard and go to the Team Settings -> API page.
- Next to Allowed redirect URIs click Configure then Add New URI.
- Enter your redirect URI, which you must also set up as a Universal Link
for your application, for example:
https://app.example.com/plaid/. - Click Save Changes.
These redirect URIs must be set up as Universal Links in your application. For details, see Apple's documentation on Allowing Apps and Websites to Link to Your Content.
Plaid does not support registering URLs with custom URL schemes as redirect URIs since they lack the security of Universal Links through the two-way association between your app and your website. Any application can register custom URL schemes and there is no further validation from iOS. If multiple applications have registered the same custom URL scheme, a different application may be launched each time the URL is opened. To complete Plaid OAuth flows, it is important that your application is opened and not any arbitrary application that has registered the same URL scheme.
Set up Universal Links
In order for Plaid to return control back to your application after a user
completes a bank's OAuth flow, you must specify a redirect URI, which will be the URI from which
Link will be re-launched to complete the OAuth flow. The redirect URI must be a
Universal Link.
An example of a typical redirect URI is: https://app.example.com/plaid.
Universal Links consist of the following parts:
- An
applinksentitlement for the Associated Domains capability in your app. For details, see Apple’s documentation on the Associated Domains Entitlement and the entitlements example in the LinkDemo-Swift example app. - An
apple-app-site-associationfile on your website. For details, see Apple’s documentation on Supporting Associated Domains and see our minimal example below.
There are a few requirements for apple-app-site-association files:
- Must be a static JSON file
- Must be hosted using a
https://scheme with a valid certificate and no redirects - Must be hosted at
https://<my-fully-qualified-domain>/.well-known/apple-app-site-association
Below is an example for https://my-app.com (https://my-app.com/.well-known/apple-app-site-association)
{
"applinks": {
"details": [
{
"appIDs": ["<My Application Identifier Prefix>.<My Bundle ID>"],
"components": [
{
"/": "/plaid/*",
"comment": "Matches any URL path whose path starts with /plaid/"
}
]
}
]
}
}Once you have enabled Universal Links, your iOS app is now set up and ready to start integrating with the Plaid SDK.
Ensure that the corresponding entry for the configured redirect URI in the apple-app-site-association file on your website continues to be available. If it is removed, OAuth sessions will fail until it is available again.
Installation
Plaid Link for iOS is an embeddable framework that is bundled and distributed with your application.
There are several ways to obtain the necessary files and keep them up-to-date; we
recommend using Swift Package Manager or CocoaPods.
Regardless of what you choose, submitting a new version of your application with the updated
LinkKit.xcframework to the App Store is required.
Requirements
| LinkKit iOS version | Xcode toolchain minimum support | Supported iOS versions |
|---|---|---|
| LinkKit 5.x.x | Xcode 15 | iOS 14 or greater |
| LinkKit 4.x.x | Xcode 14 | iOS 11 or greater |
| LinkKit 3.x.x | Xcode 13 | iOS 11 or greater |
Swift Package Manager
- To integrate LinkKit using Swift Package Manager, Swift version >= 5.3 is required.
- In your Xcode project from the Project Navigator (Xcode ❯ View ❯ Navigators ❯ Project ⌘ 1)
select your project, activate the Package Dependencies tab and click on the plus symbol ➕
to open the Add Package popup window:

- Enter the LinkKit package URL
https://github.com/plaid/plaid-link-ios-spminto the search bar in the top right corner of the Add Package popup window. The main repository with full git history is very large (~1 GB), and Swift Package Manager always downloads the full repository with all git history. Thisplaid-link-ios-spmrepository is much smaller (less than 500kb), making the download faster. - Select the
plaid-link-ios-spmpackage. - Choose your Dependency Rule (we recommend Up to Next Major Version).
- Select the project to which you would like to add LinkKit, then click Add Package:

- Select the
LinkKitpackage product and click Add Package:
- Verify that the LinkKit Swift package was properly added as a package dependency to your project:

- Select your application target and ensure that the LinkKit library is embedded into your application:

CocoaPods
- If you haven’t already, install the latest version of CocoaPods.
- If you don’t have an existing Podfile, run the following command to create one:Create a new Podfile
pod init - Add this line to your
Podfile:Edit the Podfile to include the following linepod 'Plaid' - Run the following command:Install the Plaid and other CocoaPods
pod install - To update to newer releases in the future, run:Update the Plaid and other CocoaPods
pod install
Manual
Get the latest version of the LinkKit.xcframework
and embed it into your application, for example by dragging and dropping the XCFramework bundle
onto the Embed Frameworks build phase of your application target in Xcode as shown below.

Camera Support (Identity Verification only)
When using the Identity Verification product, the Link SDK may use the camera if a user
needs to take a picture of identity documentation. To support this workflow, add a NSCameraUsageDescription entry to your application's plist
with an informative string. This allows iOS to prompt the user for camera access. iOS will crash your application if
this string is not provided.
Upgrading
New versions of LinkKit.xcframework
are released frequently. Major releases occur annually. The Link SDK uses Semantic Versioning, ensuring that all non-major releases are non-breaking, backwards-compatible updates. We recommend you update regularly (at least once a quarter, and ideally once a month) to ensure the best Plaid Link experience in your application.
SDK versions are supported for two years; with each major SDK release, Plaid will stop officially supporting any previous SDK versions that are more than two years old. While these older versions are expected to continue to work without disruption, Plaid will not provide assistance with unsupported SDK versions.
For details on each release see the GitHub releases and version release notes.
Opening Link
Before you can open Link, you need to first create a link_token. A link_token can be configured for
different Link flows and is used to control much of Link’s behavior. To learn how to create a new
link_token, see the API Reference entry for /link/token/create.
For iOS the /link/token/create call must include the redirect_uri parameter and it must
match the redirect URI you have configured with Plaid
(see Register your redirect URI above).
Create a Configuration
Starting the Plaid Link for iOS experience begins with creating a link_token. Once the link_token is passed to your app, create an instance of LinkTokenConfiguration, then create a Handler using Plaid.create() passing the previously created LinkTokenConfiguration. Plaid will begin to pre-load Link as soon as Plaid.create() is called, so to reduce UI latency when rendering Link, you should call Plaid.create() when initializing the screen where the user can enter the Link flow.
After calling Plaid.create(), to show the Link UI, call open() on the handler passing your preferred presentation method.
Note that each time you open Link, you will need to get a new link_token from your server and create a new LinkTokenConfiguration with it.
Properties
tokenlink_token to authenticate your app with Link. This is a short lived, one-time use token that should be unique for each Link session. In addition to the primary flow, a link_token can be configured to launch Link in update mode. See the /link/token/create endpoint for more details.var linkConfiguration = LinkTokenConfiguration(
token: "<#LINK_TOKEN_FROM_SERVER#>",
onSuccess: { linkSuccess in
// Send the linkSuccess.publicToken to your app server.
}
)
// Optional: Configure additional Link presentation options.
// If true, skips the default Link loading animation.
// Use this if you're displaying your own custom loading UI.
linkConfiguration.noLoadingState = true
// Optional: Configure additional Link presentation options -
// Available in SDK v6.2.0 and above:
// If false, displays a solid background instead of the default
// transparent gradient.
linkConfiguration.showGradientBackground = false
Create a Handler
A Handler is a one-time use object used to open a Link session. The Handler must
be retained for the duration of the Plaid SDK flow. It will also be needed to respond to OAuth Universal Link
redirects. For more details, see the OAuth guide.
You can optionally provide an onLoad (available in SDK v6.2.0 and above) callback to know when Link has finished preloading and is ready to be presented. This is useful if you want to delay presenting Link until it’s fully loaded, or enable related UI elements.
Note for Layer customers: You should wait for the LAYER_READY event before presenting Link, rather than relying solely on onLoad.
let result = Plaid.create(configuration, onLoad: { [weak self] in
// Optional callback that is invoked once Plaid Link has
// finished loading and is ready to be presented.
// You could use your own loading UI and automatically
// launch Link when this callback fires.
//
// Ex:
// guard let self = self else { return }
// self.handler?.open(presentUsing: .viewController(self))
//
// Ex: Enable a button once Link has loaded
// self?.openButton.isEnabled = true
})
switch result {
case .failure(let error):
logger.error("Unable to create Plaid handler due to: \(error)")
case .success(let handler):
self.handler = handler
}
Open Link
Finally, open Link by calling open on the Handler object.
This will usually be done in a button’s target action.
let method: PresentationMethod = .viewController(self)
handler.open(presentUsing: method)
onSuccess
The closure is called when a user successfully links an Item. It should take a single LinkSuccess argument, containing the publicToken String and a metadata of type SuccessMetadata.
Properties
linkSuccesspublicToken and metadata for this successful flow.publicTokennull. If using Document Income or Payroll Income, the public_token will be returned, but is not used.metadatainstitutionnull.nameinstitutionIDaccountsidaccount_idnamemasksubtypeverificationStatuspending_automatic_verification: The Item is pending automatic verification.pending_manual_verification: The Item is pending manual micro-deposit verification. Items remain in this state until the user successfully verifies the deposit.automatically_verified: The Item has successfully been automatically verified.manually_verified: The Item has successfully been manually verified.verification_expired: Plaid was unable to automatically verify the deposit within 7 calendar days and will no longer attempt to validate the Item. Users may retry by submitting their information again through Link.verification_failed: The Item failed manual micro-deposit verification because the user exhausted all 3 verification attempts. Users may retry by submitting their information again through Link.database_matched: The Item has successfully been verified using Plaid's data sources.database_insights_pending: The Database Insights result is pending and will be available upon Auth request.nil: Neither micro-deposit-based verification nor database verification are being used for the Item.linkSessionIDmetadataJSONonSuccess: { linkSuccess in
// Send the linkSuccess.publicToken to your app server.
}
onExit
This optional closure is called when a user exits Link without successfully linking an Item, or when an error occurs during Link initialization. It should take a single LinkExit argument, containing an optional error and a metadata of type ExitMetadata.
Properties
linkExiterror and metadata for when the flow was exited.errorerrorCode, errorMessage, and displayMessage of the error that was last encountered by the user. If no error was encountered, error will be nil. In Objective-C, field names will match the NSError type.errorCodeerrorCode has an associated errorType, which is a broad categorization of the error.errorMessagedisplayMessagenil if the error is not related to user action. This may change over time and is not safe for programmatic use.metadatastatusrequiresQuestionsrequiresSelectionsrequiresCodechooseDevicerequiresCredentialsrequiresAccountSelectioninstitutionNotFoundinstitutionNotSupportedunknownunknown case has an associated value carrying the original exit status as sent by the Plaid API.institutioninstitutionIDnamelinkSessionIDrequestIDmetadataJSONlinkConfiguration.onExit = { linkExit in
// Optionally handle linkExit data according to your application's needs
}
onEvent
This closure is called when certain events in the Plaid Link flow have occurred. The open, layerReady, layerNotAvailable, layerAutofillNotAvailable events are guaranteed to fire in real time; other events will typically be fired when the Link session finishes, when onSuccess or onExit is called. Callback ordering is not guaranteed; onEvent callbacks may fire before, after, or surrounding the onSuccess or onExit callback, and event callbacks are not guaranteed to fire in the order in which they occurred.
The following onEvent callbacks are stable, which means that they are suitable for programmatic use in your application's logic: open, exit, handoff, selectInstitution, error, bankIncomeInsightsCompleted, identityVerificationPassSession, identityVerificationFailSession, layerReady, layerNotAvailable, layerAutofillNotAvailable. The remaining callback events are informational and subject to change, and should be used for analytics and troubleshooting purposes only.
Properties
linkEventeventName and metadata for the Link event.eventNameautoSubmitPhone/link/token/create call and the user has previously consented to receive OTP codes from Plaid.bankIncomeInsightsCompletedcloseOAuthconnectNewInstitutionerrorerrorCode in the metadata.failOAuthhandoffidentityMatchFailedidentityMatchPassedidentityVerificationStartStepview_name.identityVerificationPassStepview_name.identityVerificationFailStepview_name.identityVerificationPendingReviewStepidentityVerificationCreateSessionidentityVerificationResumeSessionidentityVerificationPassSessionidentityVerificationFailSessionidentityVerificationPendingReviewSessionidentityVerificationOpenUIidentityVerificationResumeUIidentityVerificationCloseUIlayerAutofillNotAvailablelayerNotAvailablelayerReadyopen() may now be called.matchedSelectInstitutionrouting_number was provided when calling /link/token/create. For details on which scenario is triggering the event, see metadata.matchReason.openopenMyPlaidopenOAuthsearchInstitutionselectAuthTypeselection metadata to indicate the user's selection.selectBrandselectDegradedInstitutionDEGRADED health status and was shown a corresponding message.selectDownInstitutionDOWN health status and was shown a corresponding message.selectFilteredInstitutionselectInstitutionskipSubmitPhonesubmitAccountNumberaccountNumberMask metadata to indicate the mask of the account number the user provided.submitCredentialssubmitDocumentssubmitDocumentsErrorsubmitDocumentsSuccesssubmitMFAsubmitOTPsubmitPhonesubmitRoutingNumberroutingNumber metadata to indicate user's routing number.transitionViewtransitionView event indicates that the user has moved from one view to the next.uploadDocumentsverifyPhoneviewDataTypesunknownunknown case has an associated value carrying the original event name as sent by the Plaid API.metadataaccountNumberMaskaccount_number_mask is empty. Emitted by SUBMIT_ACCOUNT_NUMBER.errorCodeerror, exit.errorMessageerror, exit.exitStatusexit.requiresQuestionsrequiresSelectionsrequiresCodechooseDevicerequiresCredentialsinstitutionNotFoundunknowninstitutionIDinstitutionNameinstitutionSearchQuerysearchInstitution.isUpdateModeOPEN.matchReasonreturning_user or routing_number if emitted by: MATCHED_SELECT_INSTITUTION.
Otherwise, this will be SAVED_INSTITUTION or AUTO_SELECT_SAVED_INSTITUTION if emitted by: SELECT_INSTITUTION.linkSessionIDlink_session_id is a unique identifier for a single session of Link. It's always available and will stay constant throughout the flow. Emitted by: all events.mfaTypecode, device, questions, selections. Emitted by: submitMFA and transitionView when viewName is mfarequestIDroutingNumberSUBMIT_ROUTING_NUMBER.selectionflow_type_manual or flow_type_instant. Emitted by: SELECT_AUTH_TYPE.timestamp2017-09-14T14:42:19.350Z. Emitted by: all events.viewNametransitionView.acceptTOSconnectedconsentcredentialdocumentaryVerificationerrorexitinstantMicrodepositAuthorizedkycCheckloadingmfanumbersnumbersSelectInstitutionoauthprofileDataReviewrecaptchariskChecksameDayMicrodepositAuthorizedscreeningselectAccountselectAuthTypeselectBrandselectInstitutionselectSavedAccountselectSavedInstitutionselfieChecksubmitPhoneuploadDocumentsverifyPhoneverifySMSunknownmetadataJSONlinkConfiguration.onEvent = { linkEvent in
// Optionally handle linkEvent data according to your application's needs
}
Submit
The submit function is currently only used in the Layer product. It allows the client application to submit additional user-collected data to the Link flow (e.g. a user phone number).
Properties
submissionDataphoneNumberdateOfBirth// Create a model that conforms to the SubmissionData interface
struct PlaidSubmitData: SubmissionData {
var phoneNumber: String?
}
let data = PlaidSubmitData(phoneNumber: "14155550015")
self.handler.submit(data)
Next steps
Once you've gotten Link working, see Link best practices for recommendations on further improving the Link flow.