Skip to main content
Privy’s exportWallet method requires a secure browser context and therefore can only be executed through the React SDK. Mobile apps built with React Native, Swift, Android, or Flutter can support key export by opening a hosted web page in a WebView. The user logs in on the hosted page and exports their key.

How it works

  1. The user taps “Export key” (or equivalent) in the native app.
  2. The app opens the hosted export page URL in a WebView.
  3. On the hosted page, the user logs in with Privy (email, OAuth, etc.) if they are not already logged in.
  4. After logging in, the user taps “Export wallet” on the page, which calls exportWallet() and shows the export modal.
  5. When export completes (or fails), the page posts a JSON result back to the native app via a messaging bridge.

Prerequisites

1. Build the export web page

Create a hosted web page where the user can log in with Privy (if needed) and then tap a button to export their wallet key. The page uses the Privy React SDK and posts the result back to the native app via a messaging bridge.
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Export wallet</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/App.tsx"></script>
  </body>
</html>
Host this page on a domain listed in the app’s allowed origins. Configure allowed origins in the Privy Dashboard.
The hosted page must use the same appId as the mobile app so that login and export work correctly for your app’s users.

2. Load the WebView in the native app

When the user taps “Export key”, open the hosted export page URL in a WebView. Use incognito or non-persistent storage so that login and export data are not cached.
import React, {useState, useRef} from 'react';
import {View, Modal, Button} from 'react-native';
import {WebView} from 'react-native-webview';

const EXPORT_PAGE_URL = 'https://your-domain.com/export';

function ExportWalletScreen() {
  const [visible, setVisible] = useState(false);
  const webViewRef = useRef(null);

  const openExport = () => setVisible(true);

  const handleMessage = (event: any) => {
    const data = JSON.parse(event.nativeEvent.data);
    if (data.status === 'success' || data.status === 'error') {
      setVisible(false);
    }
  };

  return (
    <View>
      <Button title="Export wallet" onPress={openExport} />
      <Modal visible={visible} animationType="slide">
        <WebView
          ref={webViewRef}
          source={{uri: EXPORT_PAGE_URL}}
          onMessage={handleMessage}
          incognito={true}
        />
      </Modal>
    </View>
  );
}

3. Handle the export result

When the hosted page completes (or encounters an error), it posts a JSON message back to the native app. Parse this message to determine the outcome and dismiss the WebView.
const handleMessage = (event: any) => {
  const data = JSON.parse(event.nativeEvent.data);

  if (data.status === 'success') {
    // Key export completed successfully. Dismiss the WebView.
    setVisible(false);
  } else if (data.status === 'error') {
    // An error occurred during export.
    console.error('Export failed:', data.error);
    setVisible(false);
  }
};

Security considerations

Keep the following in mind when implementing the WebView-based export flow:
  • Ephemeral WebViews: Use incognito or non-persistent data store modes (shown in the examples above) so that login and export data are not cached on the device.
  • Separate origin: The private key is assembled on a different origin from the app and the hosted page. Neither the app nor the page can access the full private key.