Requirements: Flutter 3.0+, Dart 3.0+, iOS 15.5+ / Android 6.0+, and a Dynamic environment ID from the Dynamic dashboard.Platform support: The Flutter SDK currently supports iOS and Android only. Web and desktop platforms are not supported at this time.
- Agent-friendly
- Visual
Add the Dynamic docs MCP to your AI editor first — your agent can then query the docs directly. Instructions are on the Welcome page.
# Flutter SDK Quickstart
## Purpose and Usage
This document provides structured quickstart information for the Dynamic Flutter SDK. It is designed to be consumed by LLMs to generate accurate installation commands and code examples based on user requirements.
**How to use this document:**
**BEFORE WRITING ANY CODE**, ask the user which path they want:
> "Would you like a **Quick start** (EVM support, zero configuration — recommended if you're just getting started) or a **Custom setup** (choose your chains and configuration)?"
Do not proceed until the user has answered. Do not assume a path.
- If the user chooses **Quick start**: follow the Quick Start Path section exactly. Do not ask any configuration questions — execute the happy path as written.
- If the user chooses **Custom setup**: follow the Custom Setup Path section and ask all configuration questions before proceeding.
---
## Quick Start Path
> Use this path when the user chooses Quick start. Execute every step in order. Do not skip steps. Do not ask configuration questions.
**Stack:** Flutter + EVM only
### Step 1 — Prerequisites
Tell the user:
- Flutter 3.0+ and Dart 3.0+ are required — verify with `flutter --version`
- iOS 15.5+ / Android 6.0+ is required
- A simulator or device must be running before Step 5 — start one now if not already running
- A Dynamic environment ID is required — get one at https://app.dynamic.xyz/dashboard/developer/api
Ask the user for their environment ID before proceeding.
### Step 2 — Install
```bash
flutter pub add dynamic_sdk dynamic_sdk_web3dart
```
### Step 3 — Initialize the SDK
In `lib/main.dart`, initialize the SDK in `main()` before `runApp()`:
```dart
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
DynamicSDK.init(
props: ClientProps(
environmentId: 'YOUR_ENVIRONMENT_ID',
appLogoUrl: 'https://demo.dynamic.xyz/favicon-32x32.png',
appName: 'My App',
),
);
runApp(const MyApp());
}
```
> `WidgetsFlutterBinding.ensureInitialized()` must be called before `DynamicSDK.init()`. Do not access `DynamicSDK.instance` before initialization.
### Step 4 — Set up the app with the Dynamic widget
The `dynamicWidget` **must always be present in the widget tree** — it provides the overlay for authentication UI. Without it, auth flows will not appear.
Replace the contents of `MyApp` in `lib/main.dart`:
```dart
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Stack(
children: [
// Wait for SDK to be ready before rendering app content
StreamBuilder<bool?>(
stream: DynamicSDK.instance.sdk.readyChanges,
builder: (context, snapshot) {
final sdkReady = snapshot.data ?? false;
return sdkReady
? const HomePage()
: const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
},
),
// dynamicWidget must always be present — handles auth UI overlay
DynamicSDK.instance.dynamicWidget,
],
),
);
}
}
```
### Step 5 — Add a home page with sign in
Create `lib/home_page.dart`:
```dart
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dynamic Demo')),
body: Center(
child: StreamBuilder<String?>(
stream: DynamicSDK.instance.auth.tokenChanges,
builder: (context, snapshot) {
final isAuthenticated = snapshot.data != null;
if (isAuthenticated) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Connected!'),
const SizedBox(height: 16),
StreamBuilder<List<BaseWallet>>(
stream: DynamicSDK.instance.wallets.userWalletsChanges,
builder: (context, walletSnapshot) {
final wallets = walletSnapshot.data ?? [];
if (wallets.isEmpty) return const CircularProgressIndicator();
return Text('Wallet: ${wallets.first.address}');
},
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => DynamicSDK.instance.auth.logout(),
child: const Text('Disconnect'),
),
],
);
}
return ElevatedButton(
onPressed: () => DynamicSDK.instance.ui.showAuth(),
child: const Text('Connect Wallet'),
);
},
),
),
);
}
}
```
Then add the import to `lib/main.dart`:
```dart
import 'home_page.dart';
```
### Step 6 — Run the app
Make sure a simulator or device is running, then:
```bash
flutter run
```
You should see a **Connect Wallet** button. Tapping it opens the Dynamic auth UI.
### Step 7 — Dashboard configuration checklist
Before testing auth, verify these settings in your Dynamic dashboard at https://app.dynamic.xyz:
1. **Login method enabled** — go to **Sign-in Methods** and enable at least one (e.g. email OTP)
2. **Embedded wallets enabled** — go to **Wallets** and enable embedded wallets
3. **Chains enabled** — go to **Chains & Networks** and enable EVM
---
## Custom Setup Path
> Use this path when the user chooses Custom setup. Ask ALL questions below before generating any code.
**Questions to ask the user:**
1. Which chains do you want to support? (EVM, SVM/Solana — one or both)
2. Do you need social auth (Google, Apple, etc.)? If so, you will need to configure deeplinks.
**Only after receiving answers**, use the sections below to generate the correct setup.
### Package Mapping
- Core (always required): `dynamic_sdk`
- EVM: `dynamic_sdk_web3dart`
- SVM (Solana): `dynamic_sdk_solana`
### Installation
```bash
flutter pub add dynamic_sdk # always required
flutter pub add dynamic_sdk_web3dart # if EVM selected
flutter pub add dynamic_sdk_solana # if SVM selected
```
### SDK Initialization
Same pattern as Quick Start — `WidgetsFlutterBinding.ensureInitialized()` → `DynamicSDK.init()` → `runApp()`.
### Valid Chain Combinations
- Core only (auth only, no chain operations)
- Core + EVM
- Core + SVM
- Core + EVM + SVM
### Documentation
All docs for this SDK: https://docs.dynamic.xyz (paths starting with `/flutter/`)
Environment ID: https://app.dynamic.xyz/dashboard/developer/api
---
## Critical Reference
| Correct | Incorrect | Notes |
|---|---|---|
| `WidgetsFlutterBinding.ensureInitialized()` before `DynamicSDK.init()` | Calling `DynamicSDK.init()` first | Flutter binding must be initialized first |
| `DynamicSDK.init()` in `main()` before `runApp()` | Initializing inside a widget | Must happen before the widget tree is built |
| `DynamicSDK.instance.dynamicWidget` always in widget tree | Omitting `dynamicWidget` | Required for auth UI overlay — auth will silently fail without it |
| `StreamBuilder` on `sdk.readyChanges` before rendering app | Using SDK before ready | SDK is async — always wait for ready state |
| `DynamicSDK.instance.auth.tokenChanges` for auth state | Polling or one-time checks | Use streams for reactive auth state |
---
## Troubleshooting
### 1 — "Could not find package 'dynamic_sdk'"
Run `flutter pub get`. If that fails, try `flutter clean && flutter pub get`.
### 2 — Auth UI not appearing
`DynamicSDK.instance.dynamicWidget` is missing from the widget tree. Add it inside a `Stack` above your app content.
### 3 — Wallets not appearing after login
Wallets are created asynchronously after authentication. Use `DynamicSDK.instance.wallets.userWalletsChanges` stream to listen for updates. Also verify embedded wallets are enabled in the dashboard.
### 4 — Social auth / OAuth redirects not working
Configure your URL scheme in `ios/Runner/Info.plist` and `android/app/src/main/AndroidManifest.xml`. Whitelist your deeplink URL in the Dynamic dashboard under **Security → Whitelist Mobile Deeplink**. See https://docs.dynamic.xyz/flutter/social-authentication.
### 5 — "SDK not initialized" error
Ensure `DynamicSDK.init()` is called in `main()` before `runApp()`, and `WidgetsFlutterBinding.ensureInitialized()` is called first.
If the issue persists, check https://docs.dynamic.xyz/overview/troubleshooting/general.
Install the SDK
Or manually add to yourpubspec.yaml:dependencies:
dynamic_sdk: ^1.2.4
flutter pub get
Initialize the SDK
Configuration Options
| Property | Description | Required |
|---|---|---|
environmentId | Your Dynamic environment ID from the dashboard | Yes |
appLogoUrl | URL to your app’s logo (shown in auth UI) | Yes |
appName | Your app’s display name | Yes |
appOrigin | Your app’s origin URL (required for passkeys and social auth) | Yes |
redirectUrl | Deep link URL scheme for social auth callbacks | No |
Access the SDK
After initialization, access the SDK singleton anywhere in your app:final sdk = DynamicSDK.instance;
Basic Usage
Using Built-in Authentication UI
The easiest way to add authentication is using the built-in UI:import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
DynamicSDK.init(
props: ClientProps(
environmentId: 'your-environment-id',
appLogoUrl: 'https://your-app.com/logo.png',
appName: 'Your App',
appOrigin: 'https://your-app.com',
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Dynamic App',
home: Stack(
children: [
const HomePage(),
// Dynamic SDK widget overlay (required for auth UI)
DynamicSDK.instance.dynamicWidget,
],
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
DynamicSDK.instance.ui.showAuth();
},
child: const Text('Sign In'),
),
),
);
}
}
Listening for Authentication State
Use StreamBuilder to react to authentication changes:import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Dynamic App',
home: Stack(
children: [
// Wait for SDK to be ready
StreamBuilder<bool?>(
stream: DynamicSDK.instance.sdk.readyChanges,
builder: (context, readySnapshot) {
final sdkReady = readySnapshot.data ?? false;
if (!sdkReady) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
// Check authentication state
return StreamBuilder<String?>(
stream: DynamicSDK.instance.auth.tokenChanges,
builder: (context, tokenSnapshot) {
final isAuthenticated = tokenSnapshot.data != null;
return isAuthenticated
? const HomeView()
: const LoginView();
},
);
},
),
// Dynamic SDK widget overlay
DynamicSDK.instance.dynamicWidget,
],
),
);
}
}
Complete Example with Wallets
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';
class HomeView extends StatelessWidget {
const HomeView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My Wallets'),
),
body: Column(
children: [
// Display authenticated user
StreamBuilder<dynamic>(
stream: DynamicSDK.instance.auth.authenticatedUserChanges,
builder: (context, snapshot) {
final user = snapshot.data;
if (user != null) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Text('Welcome, ${user.email ?? "User"}!'),
);
}
return const SizedBox.shrink();
},
),
// Display wallets
Expanded(
child: StreamBuilder<List<BaseWallet>>(
stream: DynamicSDK.instance.wallets.userWalletsChanges,
builder: (context, snapshot) {
final wallets = snapshot.data ?? [];
if (wallets.isEmpty) {
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: wallets.length,
itemBuilder: (context, index) {
final wallet = wallets[index];
return ListTile(
title: Text(wallet.address),
subtitle: Text('Chain: ${wallet.chain}'),
);
},
);
},
),
),
// Logout button
Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
onPressed: () async {
await DynamicSDK.instance.auth.logout();
},
child: const Text('Logout'),
),
),
],
),
);
}
}
Enable Features in Dashboard
Before you can use authentication and wallet features, enable them in your Dynamic dashboard:- Go to your Dynamic Dashboard
- Select your project
- Go to Authentication and enable the methods you want to use:
- Email OTP
- SMS OTP
- Social providers (Google, Apple, Discord, Farcaster, GitHub, Twitter, Facebook)
- Go to Wallets and enable embedded wallets
- Go to Chains and enable the networks you want to support (EVM and/or Solana)
For testing, we recommend starting with Email OTP authentication and an EVM
testnet like Base Sepolia. This gives you a complete setup without requiring
real phone numbers or mainnet transactions.
Troubleshooting
Common Issues
-
Could not find package ‘dynamic_sdk’
- Make sure you’ve added the package to your
pubspec.yaml - Run
flutter pub get - Try
flutter clean && flutter pub get
- Make sure you’ve added the package to your
-
SDK not initialized
- Ensure
DynamicSDK.init()is called inmain()beforerunApp() - Don’t access
DynamicSDK.instancebefore initialization
- Ensure
-
Authentication callbacks not working
- Verify your URL scheme is configured in your iOS Info.plist
- For Android, configure the deeplink scheme in AndroidManifest.xml
- Ensure the
redirectUrlmatches your URL scheme - Whitelist your deep link URL in the Dynamic dashboard under Security → Whitelist Mobile Deeplink
- See Social Authentication for detailed setup
-
Wallets not appearing after login
- Wallets are created asynchronously after authentication
- Use
DynamicSDK.instance.wallets.userWalletsChangesstream to listen for wallet updates - Check that embedded wallets are enabled in your dashboard
- See Wallet Creation for details
-
Session state not updating
- Make sure you’re using
StreamBuilderto observe state changes - Verify that
DynamicSDK.instance.dynamicWidgetis included in your widget tree (required) - Check that streams are being properly subscribed to
- Make sure you’re using
-
UI not showing
- The
DynamicSDK.instance.dynamicWidgetmust be in your widget tree (typically in a Stack) - This widget provides the overlay for authentication and profile UI
- Position it above your main content in a Stack
- The
Next Steps
Great! Your SDK is now configured and ready to use. Here’s what you can do next:- Introduction - Learn about all SDK features and architecture
- Client Setup - Detailed SDK configuration and modules
- Authentication Guide - Implement email, SMS, and OTP authentication
- Social Authentication - Add social login options
- Session Management - Manage authenticated sessions with Streams
- Wallet Operations - Work with balances and sign messages
- Networks - Configure blockchain networks
📱 Complete Example App: For a fully functional Flutter app demonstrating all SDK
features, check out our Flutter SDK Example App. It
includes authentication flows (email/SMS OTP, social login), wallet management, EVM/Solana transactions,
and more.
Additional Resources
- Go Router Integration - Integrate with go_router for navigation
- Web3Dart Integration - Deep dive into EVM blockchain interactions
- Solana Integration - Deep dive into Solana blockchain interactions
- SDK Reference - Complete API documentation