Export Private Key

The Alchemy Signer allows you to export a user’s private key, allowing them a right to exit at any time. It is considered a best practice to allow your users to export their private key, as it gives them full control over their account. The private key export method does not rely on Alchemy’s infrastructure, so even if Alchemy is down, a user can still export their private key.

Using useExportAccount

A hook use to export the private key for an account. It returns the mutation functions to kick off the export process, as well as a component to render the account recovery details in an iframe.

Import

1import { useExportAccount } from "@account-kit/react";

Usage

1import { useExportAccount } from "@account-kit/react";
2
3const {
4 exportAccount,
5 isExported,
6 isExporting,
7 error,
8 ExportAccountComponent,
9} = useExportAccount({
10 params: {
11 iframeContainerId: "my-iframe-container",
12 },
13});

Using the signer

To add export private key functionality to your app, you can use the exportPrivateKey method on the signer.

import React from "react";
import { 
function useMutation<TData = unknown, TError = Error, TVariables = void, TContext = unknown>(options: UseMutationOptions<TData, TError, TVariables, TContext>, queryClient?: QueryClient): UseMutationResult<TData, TError, TVariables, TContext>
useMutation
} from "@tanstack/react-query";
import {
import signer
signer
} from "./signer";
const
const TurnkeyExportWalletContainerId: "turnkey-export-wallet-container-id"
TurnkeyExportWalletContainerId
= "turnkey-export-wallet-container-id";
const
const TurnkeyExportWalletElementId: "turnkey-export-wallet-element-id"
TurnkeyExportWalletElementId
= "turnkey-export-wallet-element-id";
// This allows us to style the embedded iframe const
const iframeCss: "\niframe {\n box-sizing: border-box;\n width: 100%;\n height: 120px;\n border-radius: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: rgba(216, 219, 227, 1);\n padding: 20px;\n}\n"
iframeCss
= `
iframe { box-sizing: border-box; width: 100%; height: 120px; border-radius: 8px; border-width: 1px; border-style: solid; border-color: rgba(216, 219, 227, 1); padding: 20px; } `; export const
const ExportPrivateKeyView: () => JSX.Element
ExportPrivateKeyView
= () => {
// we are using react-query to handle loading states more easily, but feel free to use w/e state management library you prefer const {
mutate: UseMutateFunction<unknown, Error, void, unknown>

The mutation function you can call with variables to trigger the mutation and optionally hooks on additional callback options.

mutate
:
const exportWallet: UseMutateFunction<unknown, Error, void, unknown>

The mutation function you can call with variables to trigger the mutation and optionally hooks on additional callback options.

exportWallet
,
const isPending: boolean

A boolean variable derived from status. true if the mutation is currently executing.

isPending
,
const data: unknown

The last successfully resolved data for the mutation.

data
,
} =
useMutation<unknown, Error, void, unknown>(options: UseMutationOptions<unknown, Error, void, unknown>, queryClient?: QueryClient): UseMutationResult<unknown, Error, void, unknown>
useMutation
({
mutationFn?: MutationFunction<unknown, void> | undefined
mutationFn
: () =>
import signer
signer
.
any
exportWallet
({
iframeContainerId: string
iframeContainerId
:
const TurnkeyExportWalletContainerId: "turnkey-export-wallet-container-id"
TurnkeyExportWalletContainerId
,
iframeElementId: string
iframeElementId
:
const TurnkeyExportWalletElementId: "turnkey-export-wallet-element-id"
TurnkeyExportWalletElementId
,
}), }); // Once the user clicks the button, a request will be sent to initialize private key export // once the request is complete, the iframe will be rendered with either // 1. the private key if the user is logged in with a passkey // 2. the seed phrase if the user is logged in with email return ( <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
className
="flex flex-col gap-2">
{!
const data: unknown

The last successfully resolved data for the mutation.

data
? (
<
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const exportWallet: (variables: void, options?: MutateOptions<unknown, Error, void, unknown> | undefined) => void

The mutation function you can call with variables to trigger the mutation and optionally hooks on additional callback options.

exportWallet
()}
React.ButtonHTMLAttributes<HTMLButtonElement>.disabled?: boolean | undefined
disabled
={
const isPending: boolean

A boolean variable derived from status. true if the mutation is currently executing.

isPending
}>
Export Wallet </
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
) : ( <
React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
strong
>Seed Phrase</
React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
strong
>
)} <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
className
="w-full"
React.HTMLAttributes<HTMLDivElement>.style?: React.CSSProperties | undefined
style
={{
StandardLonghandProperties<string | number, string & {}>.display?: Property.Display | undefined

The display CSS property sets whether an element is treated as a block or inline element and the layout used for its children, such as flow layout, grid or flex.

Syntax: [ <display-outside> || <display-inside> ] | <display-listitem> | <display-internal> | <display-box> | <display-legacy>

Initial value: inline

| Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | 1 | 1 | 1 | 12 | 4 |

display
: !
const data: unknown

The last successfully resolved data for the mutation.

data
? "none" : "block" }}
React.HTMLAttributes<HTMLDivElement>.id?: string | undefined
id
={
const TurnkeyExportWalletContainerId: "turnkey-export-wallet-container-id"
TurnkeyExportWalletContainerId
}
> <
React.JSX.IntrinsicElements.style: React.DetailedHTMLProps<React.StyleHTMLAttributes<HTMLStyleElement>, HTMLStyleElement>
style
>{
const iframeCss: "\niframe {\n box-sizing: border-box;\n width: 100%;\n height: 120px;\n border-radius: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: rgba(216, 219, 227, 1);\n padding: 20px;\n}\n"
iframeCss
}</
React.JSX.IntrinsicElements.style: React.DetailedHTMLProps<React.StyleHTMLAttributes<HTMLStyleElement>, HTMLStyleElement>
style
>
</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
); };
import { 
class AlchemyWebSigner

A SmartAccountSigner that can be used with any SmartContractAccount

AlchemyWebSigner
} from "@account-kit/signer";
export const
const signer: AlchemyWebSigner
signer
= new
new AlchemyWebSigner(params: AlchemySignerParams): AlchemyWebSigner

Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.

AlchemyWebSigner
({
client: ({ connection: { apiKey: string; rpcUrl?: undefined; jwt?: undefined; } | { jwt: string; rpcUrl?: undefined; apiKey?: undefined; } | { rpcUrl: string; apiKey?: undefined; jwt?: undefined; } | { rpcUrl: string; jwt: string; apiKey?: undefined; }; ... 4 more ...; enablePopupOauth?: boolean | undefined; } | AlchemySignerWebClient) & (AlchemySignerWebClient | ... 1 more ... | undefined)
client
: {
connection: { apiKey: string; }
connection
: {
apiKey: string
apiKey
: "API_KEY",
},
iframeConfig: { iframeContainerId: string; }
iframeConfig
: {
iframeContainerId: string
iframeContainerId
: "alchemy-signer-iframe-container",
}, }, });