@turnkey/sdk-browser

A SDK client with browser-specific abstractions for interacting with Turnkey API. Also includes @turnkey/http, a lower-level, fully typed HTTP client.
Turnkey API documentation lives here: https://docs.turnkey.com.
Getting started
$ npm install @turnkey/sdk-browser
Initialize
import { Turnkey } from "@turnkey/sdk-browser";
const turnkey = new Turnkey({
apiBaseUrl: "https://api.turnkey.com",
defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID,
rpId: process.env.TURNKEY_RP_ID,
});
Turnkey Clients
Passkey
The Passkey client allows for authentication to Turnkey's API using Passkeys.
const passkeyClient = turnkey.passkeyClient();
await passkeyClient.login();
const walletsResponse = await passkeyClient.getWallets();
Iframe
The Iframe client can be initialized to interact with Turnkey's hosted iframes for sensitive operations.
The iframeContainer parameter is required, and should be a reference to the DOM element that will host the iframe.
The iframeUrl is the URL of the iframe you wish to interact with.
The example below demonstrates how to initialize the Iframe client for use with Email Auth
by passing in https://auth.turnkey.com as the iframeUrl.
const iframeClient = await turnkey.iframeClient({
iframeContainer: document.getElementById("<iframe container id>"),
iframeUrl: "https://auth.turnkey.com",
});
const injectedResponse = await iframeClient.injectCredentialBundle(
"<Credential from Email>",
);
if (injectedResponse) {
await iframeClient.getWallets();
}
IFrame URLs:
Wallet
The Wallet client is designed for using your Solana or EVM wallet to stamp and approve activity requests for Turnkey's API.
This stamping process leverages the wallet's signature to authenticate requests.
The example below showcases how to use an injected Ethereum wallet to stamp requests to Turnkey's API.
The user will be prompted to sign a message containing the activity request payload to be sent to Turnkey.
import {
createWalletClient,
custom,
recoverPublicKey,
hashMessage,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { WalletStamper, EthereumWallet } from "@turnkey/wallet-stamper";
const walletClient = turnkey.walletClient(new EthereumWallet());
const walletsResponse = await walletClient.getWallets();
Helpers
@turnkey/sdk-browser provides TurnkeySDKBrowserClient, which offers wrappers around commonly used Turnkey activities, such as creating new wallets and wallet accounts.
IndexedDB Sessions (Recommended)
Turnkey now supports persistent, secure, non-extractable authentication using P-256 passkeys stored in IndexedDB. This replaces legacy iframe-based flows for otp, passkey, and OAuth authentication.
The TurnkeyIndexedDbClient provides a long-lived session mechanism where the private key never leaves the browser and is scoped per sub-organization. This client handles login, session persistence, and API request signing entirely on the client side — without requiring iframes or sensitive credential injection.
import { Turnkey } from "@turnkey/sdk-browser";
const turnkey = new Turnkey({
apiBaseUrl: "https://api.turnkey.com",
defaultOrganizationId: "<YOUR_PARENT_ORG_ID>",
rpId: "<YOUR_WEBAUTHN_RELYING_PARTY_ID>",
});
const client = turnkey.indexedDbClient();
const passkeyClient = turnkey.passkeyClient();
const pubKey = await indexedDbClient!.getPublicKey();
await passkeyClient?.loginWithPasskey({
sessionType: SessionType.READ_WRITE,
publicKey: pubKey!,
expirationSeconds: "3600",
});
const wallets = await client.getWallets();
💡 Why IndexedDB?
Keys are stored using the Web Crypto API, marked as nonExtractable, and survive page reloads — offering persistent, tamper-resistant authentication without ever exposing the raw key material.
⚠️ Deprecated: iframeClient for Auth
Authentication via iframeClient() and injected credentials (e.g., from https://auth.turnkey.com) is now considered deprecated for new integrations. These flows required sensitive credential bundles to be delivered via email or OAuth and injected into a sandboxed iframe — a pattern with limited persistence and higher complexity.
Developers are encouraged to migrate to indexedDbClient() for:
- Seamless passkey authentication
- Improved security model (no credential injection)
- Long-lived, resumable sessions
Existing iframe use cases like Email Recovery, Wallet Import, and Wallet Export are still supported but should be isolated from authentication logic.