The ParaProvider component wraps your React application to provide access to Para hooks and manage the SDK instance.
ParaProvider includes an embedded ParaModal by default. Do not render another <ParaModal /> in the same provider tree unless you set config={{ disableEmbeddedModal: true }} and intentionally manage the separate modal yourself.
Import
import { ParaProvider } from "@getpara/react-sdk";
Usage
import { ParaProvider } from "@getpara/react-sdk";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<ParaProvider
paraClientConfig={{
apiKey: "your-api-key",
}}>
<YourApp />
</ParaProvider>
</QueryClientProvider>
);
}
Modal Ownership
Use the embedded modal in ParaProvider for the standard setup. Pass modal options through paraModalConfig instead of rendering a separate ParaModal:
<ParaProvider
paraClientConfig={{ apiKey: "your-api-key" }}
config={{ appName: "My App" }}
paraModalConfig={modalOptions}
>
<YourApp />
</ParaProvider>
If your app must render its own ParaModal, disable the embedded modal on the provider:
<ParaProvider
paraClientConfig={{ apiKey: "your-api-key" }}
config={{
appName: "My App",
disableEmbeddedModal: true,
}}
>
<YourApp />
<ParaModal {...modalOptions} />
</ParaProvider>
Loading State
By default, ParaProvider blocks rendering until the SDK is ready. You can customize this behavior:
With Fallback UI
Show a loading indicator instead of a blank screen while the SDK initializes:
<ParaProvider
paraClientConfig={{ apiKey: "your-api-key" }}
config={{ appName: "My App" }}
fallback={<LoadingSpinner />}
>
<YourApp />
</ParaProvider>
Render children immediately and let them handle the loading state using useParaStatus():
<ParaProvider
paraClientConfig={{ apiKey: "your-api-key" }}
config={{ appName: "My App" }}
waitForReady={false}
>
<YourApp />
</ParaProvider>
import { useParaStatus } from "@getpara/react-sdk";
function YourApp() {
const { isReady } = useParaStatus();
if (!isReady) return <LoadingSpinner />;
return <Dashboard />;
}
Advanced Usage
With Event Callbacks
function AppWithCallbacks() {
return (
<QueryClientProvider client={queryClient}>
<ParaProvider
paraClientConfig={{
apiKey: process.env.REACT_APP_PARA_API_KEY,
}}
callbacks={{
onLogin: (event) => {
console.log("User logged in:", event.detail.data);
navigate("/dashboard");
},
onLogout: (event) => {
console.log("User logged out");
clearUserData();
navigate("/");
},
onWalletCreated: (event) => {
console.log("New wallet:", event.detail.data);
toast.success("Wallet created successfully!");
},
onSignMessage: (event) => {
console.log("Message signed:", event.detail.data);
analytics.track("message_signed", {
walletType: event.detail.data.walletType
});
}
}}>
<YourApp />
</ParaProvider>
</QueryClientProvider>
);
}
With Custom Para Instance
This can be useful if you need to use the Para instance outside of the React tree, i.e. in the callbacks on the ParaProvider.
function AppWithCustomClient() {
const paraClient = useMemo(() => {
return new ParaWeb("your-api-key", {
debugMode: true,
customHeaders: {
"X-Custom-Header": "value"
}
});
}, []);
return (
<QueryClientProvider client={queryClient}>
<ParaProvider
paraClientConfig={paraClient}
{/* Optional additional ParaProvider config */}
config={{
disableAutoSessionKeepAlive: false
}}>
<YourApp />
</ParaProvider>
</QueryClientProvider>
);
}
Notes
- The
ParaProvider must wrap any components that use Para hooks
- It requires
QueryClientProvider from React Query as a parent
- Event callbacks receive events with a
detail property containing data and optional error
- The provider automatically manages session keep-alive unless disabled
- The provider automatically renders the modal unless
config.disableEmbeddedModal is set to true
- By default, children are not rendered until the SDK is ready. Use
fallback to show loading UI, or waitForReady={false} to render children immediately
- All child components can access Para hooks without additional setup