Skip to main content

Mobile SDK

The Kryptos Connect Mobile SDK provides React Native components for iOS and Android applications. It works with both Expo and React Native CLI.

Before you begin

Make sure you have completed the prerequisites in the overview and set up your backend server.

Installation

npm install @kryptos_connect/mobile-sdk react-native-webview

iOS (React Native CLI only):

cd ios && pod install

Prerequisites

Quick Start

import { KryptosConnect, KryptosConnectButton } from "@kryptos_connect/mobile-sdk";

// 1. Initialize once (or on every render to keep config in sync)
KryptosConnect.init({
clientId: "your-client-id",
appName: "My App",
appLogo: "https://yourapp.com/logo.png",
theme: "light", // "light" | "dark" | "auto"
language: "en",
authMethods: ["email", "anonymous"],
});

// 2. Drop in the button
<KryptosConnectButton
generateLinkToken={generateLinkToken}
onConnectSuccess={(consent) => console.log(consent.public_token)}
onConnectError={(err) => console.error(err)}
buttonLabel="Connect Kryptos"
buttonHeight={52}
/>;

Full Example

import { KryptosConnect, KryptosConnectButton } from "@kryptos_connect/mobile-sdk";
import { useState } from "react";

const BASE_URL = "https://connect-api.kryptos.io";
const CLIENT_ID = "your-client-id";
const CLIENT_SECRET = "your-client-secret"; // keep server-side in production
const SCOPES = "openid profile offline_access email portfolios:read integrations:read";

export default function App() {
const [accessToken, setAccessToken] = useState(null);

KryptosConnect.init({
clientId: CLIENT_ID,
appName: "My App",
theme: "light",
language: "en",
authMethods: ["email", "anonymous"],
});

async function generateLinkToken(existingAccessToken?: string | null) {
const body: Record<string, unknown> = { scopes: SCOPES };
if (existingAccessToken) body.access_token = existingAccessToken;

const res = await fetch(`${BASE_URL}/link-token`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Client-Id": CLIENT_ID,
"X-Client-Secret": CLIENT_SECRET,
},
body: JSON.stringify(body),
});
const data = await res.json();
return { link_token: data.data.link_token, isAuthorized: !!existingAccessToken };
}

async function handleSuccess(consent) {
if (!consent) return; // re-auth — no new token
const res = await fetch(`${BASE_URL}/token/exchange`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
public_token: consent.public_token,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
}),
});
const data = await res.json();
setAccessToken(data.data.access_token);
}

return (
<>
{/* Default button */}
<KryptosConnectButton
generateLinkToken={() => generateLinkToken()}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
buttonLabel="Link Kryptos Account"
buttonHeight={52}
/>

{/* Pre-select a specific integration with custom style */}
<KryptosConnectButton
generateLinkToken={() => generateLinkToken()}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
integrationName="coinbase"
buttonLabel="Connect Coinbase"
buttonHeight={48}
style={{ borderRadius: 10, backgroundColor: "#0052FF" }}
/>

{/* Re-authorize with stored access token */}
{accessToken && (
<KryptosConnectButton
generateLinkToken={() => generateLinkToken(accessToken)}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
buttonLabel="Continue with Access Token"
buttonHeight={52}
/>
)}
</>
);
}

User Flow Variations

The SDK handles two flows based on the isAuthorized flag returned from generateLinkToken:

Flow 1: New User (isAuthorized: false or undefined)

press → AUTH → INTEGRATION → onConnectSuccess({ public_token })

Exchange public_token server-side for a long-lived access_token.

Flow 2: Returning User (isAuthorized: true)

press → INTEGRATION → onConnectSuccess(null)

Pass stored access_token in the link-token request body and return isAuthorized: true. No new token is issued.

KryptosConnect.init Config

KeyTypeRequiredDescription
clientIdstringYesYour Kryptos client ID.
appNamestringYesDisplayed in the connect UI header.
appLogostringNoURI to your app logo shown in the connect UI.
walletConnectProjectIdstringNoRequired if using WalletConnect.
theme"light" | "dark" | "auto"NoUI theme. Default "light".
languagestringNoUI language. Supported: en fr de pt sv es pl it.
authMethods("email" | "anonymous")[]NoAuth methods shown. Default: both.
detectUsedChainsbooleanNoDetect which chains an EVM address is active on. Default true.
autoSelectAllChainsbooleanNoPre-select every detected chain. Default true.
cssVarsRecord<string, string>NoOverride --kc-* CSS variables in the connect UI. --kc-primary and --kc-primary-text also apply to the native button.

Restricting Auth Methods

// Email only
KryptosConnect.init({
clientId: "your-client-id",
appName: "My App",
authMethods: ["email"],
});

// Anonymous only
KryptosConnect.init({
clientId: "your-client-id",
appName: "My App",
authMethods: ["anonymous"],
});

Setting the Language

CodeLanguage
"en"English
"fr"French
"de"German
"pt"Portuguese
"sv"Swedish
"es"Spanish
"pl"Polish
"it"Italian

KryptosConnectButton Props

PropTypeRequiredDescription
generateLinkToken() => Promise<{ link_token: string; isAuthorized?: boolean }>YesCalled on press. Return isAuthorized: true to skip auth for existing users.
onConnectSuccess(data: UserConsent | null) => voidYesCalled on success. data is null when isAuthorized was true.
onConnectError(error: Error) => voidYesCalled on error or dismissal.
integrationNamestringNoSkip the integration list and open a specific integration directly.
buttonLabelstringNoButton text.
buttonHeightnumberNoButton height in dp. Default 56.
extraConfigRecord<string, unknown>NoPer-button config overrides merged onto the global config. Pass prefill here to pre-populate integration form fields.
styleStyleProp<ViewStyle>NoStyle for the button. backgroundColor overrides --kc-primary for that button.

Pre-filling Integration Forms

Pass a prefill object inside extraConfig to pre-populate the integration form when the user reaches the connection step. All fields are optional — pass only the ones you have.

FieldTypeDescription
prefill.addressstringWallet or blockchain address. Triggers chain auto-detect for EVM wallets.
prefill.apiKeystringAPI key for exchange or API-based integrations.
prefill.secretKeystringSecret key for integrations that require one.
prefill.passwordstringPassword for integrations that require one.
prefill.accountNamestringAccount name for account-based integrations.
// Pre-fill a wallet address — chains are auto-detected
<KryptosConnectButton
generateLinkToken={generateLinkToken}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
integrationName="ethereum"
buttonLabel="Connect Wallet"
extraConfig={{ prefill: { address: "0x1234567890123456789012345678901234567890" } }}
/>

// Pre-fill API credentials for an exchange
<KryptosConnectButton
generateLinkToken={generateLinkToken}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
integrationName="binance"
buttonLabel="Connect Binance"
extraConfig={{ prefill: { apiKey: "user-api-key", secretKey: "user-secret-key" } }}
/>
info

Prefilled values populate the form as editable defaults — the user can still change them before submitting. For EVM wallets, providing an address automatically triggers chain detection and pre-selects all detected chains. Use EVM chain detection to change that behaviour.

EVM chain detection

When a user enters an EVM address — by typing it or via prefill — the connect UI looks the address up to discover which chains it has activity on, then offers those chains for selection so the user can connect them all at once.

Two booleans control this. Both can be set globally in KryptosConnect.init or per-button inside extraConfig.

KeyTypeDefaultDescription
detectUsedChainsbooleantrueWhether the address is looked up at all. When false, no lookup happens and only the chain the flow was initiated with (from integrationName) is connected, as a single integration.
autoSelectAllChainsbooleantrueWhether every detected chain is pre-selected. When false, only the initiating chain is selected — the others are still listed, but the user opts into each one.

Both default to true, so the default behaviour is: detect every chain the address is active on and pre-select all of them.

Combinations

detectUsedChainsautoSelectAllChainsResult
truetrueChains are looked up and all are pre-selected. (default)
truefalseChains are looked up and listed, but only the initiating chain is pre-selected.
false(any)No lookup. The initiating chain is connected as a single integration; autoSelectAllChains is ignored.

Examples

Detect chains, but let the user opt into each one beyond the chain they picked:

<KryptosConnectButton
generateLinkToken={generateLinkToken}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
integrationName="ethereum"
buttonLabel="Connect Wallet"
extraConfig={{
prefill: { address: "0x1234567890123456789012345678901234567890" },
detectUsedChains: true,
autoSelectAllChains: false,
}}
/>

Skip chain detection entirely and connect only Ethereum:

<KryptosConnectButton
generateLinkToken={generateLinkToken}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
integrationName="ethereum"
buttonLabel="Connect Wallet"
extraConfig={{
prefill: { address: "0x1234567890123456789012345678901234567890" },
detectUsedChains: false,
}}
/>

Turn detection off globally for every button:

KryptosConnect.init({
clientId: "your-client-id",
appName: "My App",
detectUsedChains: false,
});
note

Both flags only affect EVM wallet integrations — other integrations are unaffected. The lookup is debounced by 500ms as the user types and re-runs whenever the address changes. If it fails or returns no chains, nothing is pre-selected, so a user is never opted into chains they did not choose.

Theming & Customization

Theme the connect UI by passing cssVars to KryptosConnect.init. The connect UI runs inside a WebView, so global stylesheet overrides have no effect. --kc-primary and --kc-primary-text also apply to the native button's background and label.

KryptosConnect.init({
clientId: "your-client-id",
appName: "My App",
cssVars: {
"--kc-primary": "#6366f1",
"--kc-primary-hover": "#4f46e5",
"--kc-primary-text": "#ffffff",
"--kc-border-focus": "#6366f1",
},
});

For per-button overrides, use the style prop. backgroundColor takes precedence over --kc-primary for that button only:

<KryptosConnectButton
generateLinkToken={generateLinkToken}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
buttonLabel="Connect Coinbase"
buttonHeight={48}
style={{ backgroundColor: "#0052FF", borderRadius: 10 }}
/>

For the complete variable reference, see Theming & Customization.

Direct Integration Flow

The integrationName prop directs users to a specific integration, bypassing the integration selection page.

Fetch available integration IDs from the public Kryptos API (see Public Endpoints - Integrations).

<KryptosConnectButton
generateLinkToken={generateLinkToken}
onConnectSuccess={handleSuccess}
onConnectError={(err) => console.error(err)}
integrationName="binance"
buttonLabel="Connect Binance"
/>
info

The integrationName value must match an integration ID from the supported providers list.

Platform Requirements

PlatformMinimum Version
iOS12.0+
AndroidAPI 21+ (Android 5.0+)
React Native0.60+
Expo SDK48+

Features

  • Cross-Platform: Single codebase for iOS and Android
  • Expo Support: Works with Expo and React Native CLI
  • WalletConnect v2: Built-in WalletConnect integration
  • Theming: Light, dark, and auto theme support with CSS variable customization
  • TypeScript: Full TypeScript support

Next steps