Skip to main content
Before you begin, make sure you have:
  • Flutter 3.0+ - The SDK requires Flutter 3.0 or later
  • Dart 3.0+ - Modern Dart features are used throughout
  • iOS 13.0+ / Android 6.0+ - For mobile platform support
  • Dynamic Account - Set up your project and get an environment ID from Dynamic Dashboard
Platform support: The Flutter SDK currently supports iOS and Android only. Web and desktop platforms are not supported at this time.

Install the SDK

Or manually add to your pubspec.yaml:
dependencies:
  dynamic_sdk: ^1.0.0
Then run:
flutter pub get

Initialize the SDK

Configuration Options

PropertyDescriptionRequired
environmentIdYour Dynamic environment ID from the dashboardYes
appLogoUrlURL to your app’s logo (shown in auth UI)Yes
appNameYour app’s display nameYes
redirectUrlDeep link URL scheme for social auth callbacksNo

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',
    ),
  );

  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,
        ],
      ),
    );
  }
}

class LoginView extends StatelessWidget {
  const LoginView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            DynamicSDK.instance.ui.showAuth();
          },
          child: const Text('Sign In with Dynamic'),
        ),
      ),
    );
  }
}

class HomeView extends StatelessWidget {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        actions: [
          IconButton(
            icon: const Icon(Icons.account_circle),
            onPressed: () {
              DynamicSDK.instance.ui.showUserProfile();
            },
          ),
        ],
      ),
      body: const Center(
        child: Text('Welcome!'),
      ),
    );
  }
}

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:
  1. Go to your Dynamic Dashboard
  2. Select your project
  3. Go to Authentication and enable the methods you want to use:
    • Email OTP
    • SMS OTP
    • Social providers (Google, Apple, Discord, Farcaster, GitHub, Twitter, Facebook)
  4. Go to Wallets and enable embedded wallets
  5. 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
  • SDK not initialized
    • Ensure DynamicSDK.init() is called in main() before runApp()
    • Don’t access DynamicSDK.instance before initialization
  • 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 redirectUrl matches 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.userWalletsChanges stream 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 StreamBuilder to observe state changes
    • Verify that DynamicSDK.instance.dynamicWidget is included in your widget tree (required)
    • Check that streams are being properly subscribed to
  • UI not showing
    • The DynamicSDK.instance.dynamicWidget must 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

Next Steps

Great! Your SDK is now configured and ready to use. Here’s what you can do next:
  1. Introduction - Learn about all SDK features and architecture
  2. Client Setup - Detailed SDK configuration and modules
  3. Authentication Guide - Implement email, SMS, and OTP authentication
  4. Social Authentication - Add social login options
  5. Session Management - Manage authenticated sessions with Streams
  6. Wallet Operations - Work with balances and sign messages
  7. 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