> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Flutter Quickstart

Get started with Dynamic's Flutter SDK to add embedded wallets, multi-chain support, and flexible authentication (email, social login, passkeys) to your mobile app in just a few lines.

<Note>
  **Requirements:** Flutter 3.0+, Dart 3.0+, iOS 15.5+ / Android 6.0+, and a Dynamic environment ID from the [Dynamic dashboard](https://app.dynamic.xyz/dashboard/developer/api).

  **Platform support**: The Flutter SDK currently supports iOS and Android only. Web and desktop platforms are not supported at this time.
</Note>

<Tabs>
  <Tab title="Agent-friendly">
    <Tip>
      Add the Dynamic docs MCP to your AI editor first — your agent can then query the docs directly.
    </Tip>

    <Tabs>
      <Tab title="Cursor">
        [Click here to add the MCP to Cursor.](https://cursor.com/en/install-mcp?name=dynamic\&config=eyJ1cmwiOiJodHRwczovL3d3dy5keW5hbWljLnh5ei9kb2NzL21jcCJ9)
      </Tab>

      <Tab title="Claude Code">
        ```bash theme={"system"}
        claude mcp add --transport http dynamic https://www.dynamic.xyz/docs/mcp
        ```
      </Tab>

      <Tab title="Codex">
        ```bash theme={"system"}
        codex mcp add dynamic --url https://www.dynamic.xyz/docs/mcp
        ```
      </Tab>

      <Tab title="Other">
        If your editor or agent supports remote HTTP MCP, add a server that points at `https://www.dynamic.xyz/docs/mcp`. The exact steps depend on the product; use its MCP documentation for URL-based or HTTP transport setup.
      </Tab>
    </Tabs>

    Copy this prompt into your LLM (e.g. Claude, ChatGPT, Cursor) to implement Dynamic in your Flutter app.

    <div data-llm-quickstart>
      ````markdown theme={"system"}
      # 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 |

      ---

      ## Step-Up Authentication

      **Required before accepting the `2026_04_01` API version** — verify your
      minimum API version in [Dashboard > Developers > API & SDK Keys](https://app.dynamic.xyz/dashboard/developer/api).

      If using the Dynamic Widget overlay, step-up prompts are handled
      automatically. **If building a headless integration, you must handle
      step-up authentication manually** using
      `DynamicSDK.instance.stepUpAuth.isStepUpRequired` and
      `DynamicSDK.instance.stepUpAuth.promptStepUpAuth`.

      Full guide: https://docs.dynamic.xyz/flutter/authentication-methods/step-up-auth/overview

      ---

      ## Device Registration

      **Required before accepting the `2026_04_01` API version** — verify your
      minimum API version in [Dashboard > Developers > API & SDK Keys](https://app.dynamic.xyz/dashboard/developer/api).

      If using the Dynamic Widget overlay, device registration is handled
      automatically. **If building a headless integration, you must manually
      check** `sdk.deviceRegistration.isDeviceRegistrationRequired` **and handle
      the completion event yourself.**

      Full guide: https://docs.dynamic.xyz/flutter/authentication-methods/device-registration

      ---

      ## 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.
      ````
    </div>
  </Tab>

  <Tab title="Visual">
    <iframe frameBorder="0" width="100%" height="600px" src="https://documentation-quickstarts.vercel.app/flutter?color-scheme=dark" allow="clipboard-write" className="rn-qs-dark">
      {' '}
    </iframe>

    <iframe frameBorder="0" width="100%" height="600px" src="https://documentation-quickstarts.vercel.app/flutter?color-scheme=light" allow="clipboard-write" className="rn-qs-light">
      {' '}
    </iframe>

    Or manually add to your `pubspec.yaml`:

    ```yaml theme={"system"}
    dependencies:
      dynamic_sdk: ^1.2.4
    ```

    Then run:

    ```bash theme={"system"}
    flutter pub get
    ```

    ## Initialize the SDK

    The quickstart embed under **Install the SDK** shows `DynamicSDK.init` and setup code. Use the table below for the main `ClientProps` fields.

    ### 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       |
    | `reownProjectId` | Reown (WalletConnect) project ID for [connecting to dApps](/flutter/wallets/global-wallets/walletconnect) | No       |

    ### Access the SDK

    After initialization, access the SDK singleton anywhere in your app:

    ```dart theme={"system"}
    final sdk = DynamicSDK.instance;
    ```

    ## Basic Usage

    ### Using Built-in Authentication UI

    The easiest way to add authentication is using the built-in UI:

    ```dart theme={"system"}
    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:

    ```dart theme={"system"}
    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

    ```dart theme={"system"}
    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](https://app.dynamic.xyz/dashboard/overview)
    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)

    <Tip>
      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.
    </Tip>

    ## 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](/flutter/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](/flutter/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

    <Warning>
      **Step-up authentication** and **device registration** are required
      before accepting the `2026_04_01` API version. If you have a headless
      integration, you must implement both manually.
      See the [upgrade guide](/overview/migrations/api/2026_04_01).
    </Warning>

    * [Step-up authentication](/flutter/authentication-methods/step-up-auth/overview)
    * [Device registration](/flutter/authentication-methods/device-registration)

    Great! Your SDK is now configured and ready to use. Here's what you can do next:

    1. **[Introduction](/flutter/introduction)** - Learn about all SDK features and architecture
    2. **[Client Setup](/flutter/client)** - Detailed SDK configuration and modules
    3. **[Authentication Guide](/flutter/authentication)** - Implement email, SMS, and OTP authentication
    4. **[Social Authentication](/flutter/social-authentication)** - Add social login options
    5. **[Session Management](/flutter/session-management)** - Manage authenticated sessions with Streams
    6. **[Wallet Operations](/flutter/wallets/general/token-balances)** - Work with balances and sign messages
    7. **[Networks](/flutter/wallets/general/network-management)** - Configure blockchain networks

    <Note>
      **📱 Complete Example App**: For a fully functional Flutter app demonstrating all SDK
      features, check out our [Flutter SDK Example App](https://github.com/dynamic-labs/flutter-sdk/tree/main/example). It
      includes authentication flows (email/SMS OTP, social login), wallet management, EVM/Solana transactions,
      and more.
    </Note>

    ## Additional Resources

    * [Go Router Integration](/flutter/go-router-integration) - Integrate with go\_router for navigation
    * [Web3Dart Integration](/flutter/web3dart) - Deep dive into EVM blockchain interactions
    * [Solana Integration](/flutter/solana) - Deep dive into Solana blockchain interactions
    * [SDK Reference](/flutter/sdk-reference/overview) - Complete API documentation
    * [Connect to dApps](/flutter/wallets/global-wallets/walletconnect) - Use WalletConnect to connect your embedded wallet to any dApp

    <Info>
      Building without the Dynamic Widget overlay? See the [Authentication screens](/flutter/authentication-methods/headless-authentication) for a full list of screens your app needs to handle.
    </Info>
  </Tab>
</Tabs>
