Capacitor SDK
Use Case
The Capacitor plugin for Link is a wrapper around the native Android and iOS SDKs for use in Capacitor-based hybrid apps. It is published to npm as @pinwheel/capacitor-sdk and supports Capacitor 6, 7, and 8.
If you are building a pure web app, use the Web SDK or React SDK instead — the Capacitor plugin only runs on iOS and Android.
Installation
Install the plugin and sync it into your native iOS and Android projects:
npm install --save @pinwheel/capacitor-sdk
npx cap syncYou can find the npm package here and the source on GitHub.
Build requirements
Capacitor
@capacitor/core6.0.0 – 8.x.
Android
- Capacitor 6 / 7: build with JDK 17. Newer JDKs may fail Gradle script analysis.
- Capacitor 8: build with JDK 21+, since
@capacitor/androidcompiles with Java source release 21.
Configuration
Some platform integrations may require camera access for verification purposes. Ensure the necessary permissions are configured in your native projects:
Android: Add the following permission to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />iOS: Add the following key and description to ios/App/App/Info.plist:
<key>NSCameraUsageDescription</key>
<string>We need access to your camera for verification purposes.</string>Usage
The Capacitor plugin exposes a single Pinwheel object with open() / close() methods and an event-listener API. Calling Pinwheel.open(...) presents Link as a full-screen native modal.
Pinwheel.open()
Pinwheel.open()Pass the Link token (and any optional flags) to launch Link:
import { Pinwheel } from '@pinwheel/capacitor-sdk';
await Pinwheel.open({
linkToken: '<LINK_TOKEN>',
useDarkMode: false,
useSecureOrigin: true,
});| Parameter | Type | Default | Description |
|---|---|---|---|
linkToken | string | required | The Link token created using the /link_tokens endpoint. |
useDarkMode | boolean | false | Render Link in dark mode. Combine this with whatever mechanism you use to track your app's theme for a consistent UX. |
useSecureOrigin | boolean | false | Load Link using the CSP-enabled secure origin. |
Pinwheel.close()
Pinwheel.close()Closes the currently presented Pinwheel modal (if any). The modal also dismisses itself automatically on exit.
await Pinwheel.close();Event listeners
The plugin emits a canonical event stream that includes every Link event with its name and payload. Convenience listeners (success, exit, error, login, loginAttempt) are also provided to mirror the patterns used by the React Native and Flutter SDKs. You can read more about Link events for the full list.
import { Pinwheel } from '@pinwheel/capacitor-sdk';
const eventHandle = await Pinwheel.addListener('event', ({ name, payload }) => {
console.log('pinwheel event', name, payload);
});
await Pinwheel.addListener('success', (payload) => {
if (payload.job === 'direct_deposit_switch') {
console.log('User has successfully updated their direct deposit.');
}
});
await Pinwheel.addListener('exit', (payload) => {
// payload is undefined on a clean exit, or a PinwheelError if an error occurred first.
console.log('exit', payload);
});
await Pinwheel.addListener('error', (error) => console.log('error', error));
await Pinwheel.addListener('login', (payload) => console.log('login', payload));
await Pinwheel.addListener('loginAttempt', (payload) => console.log('loginAttempt', payload));
// Remember to clean up when your view unmounts:
await eventHandle.remove();
// or remove every listener at once:
await Pinwheel.removeAllListeners();The full list of supported event names and their payload shapes (PinwheelEvent, PinwheelSuccessPayload, PinwheelError, PinwheelLoginPayload, etc.) is exported from the package and visible in src/definitions.ts.
Example Project
The plugin repository ships with three example apps — one for each supported Capacitor major (6, 7, and 8) — that exercise the full SDK against a running backend. See the example app README on GitHub.
Maintenance
Pinwheel regularly releases improvements to this SDK. You should update to the latest version of the Capacitor SDK at least quarterly to ensure the best product performance.
You can check out the full changelog here on GitHub.
Updated about 16 hours ago