# Get started with Connect embedded components

Learn how to embed dashboard functionality into your website.

Use Connect embedded components to add connected account dashboard functionality to your website. These libraries and their supporting API allow you to grant your users access to Stripe products directly in your dashboard and mobile applications.

- **Add integrated UI**: Use embedded components to add integrated UI to your Dashboard. See [all available components](https://docs.stripe.com/connect/supported-embedded-components.md).
- **Customize appearance**: Adjust the [appearance](https://docs.stripe.com/connect/customize-connect-embedded-components.md) to match your brand.
- **Stay current**: Connect embedded components stay in sync with Stripe APIs, which helps keep your integration up to date.

## Set up StripeConnect [Client-side] [Server-side]

Stripe uses an [AccountSession](https://docs.stripe.com/api/account_sessions.md) to express your intent to delegate API access to your connected account.

The AccountSessions API returns a *client secret* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components) that allows an embedded component to access a connected account’s resources as if you were making the API calls for them.

### Create an AccountSession (Server)

Your app must initiate a request to your server to obtain the account session. You can create a new endpoint on your server that returns the client secret to the app:

#### Ruby

```ruby
require 'sinatra'
require 'stripe'
# This is a placeholder - it should be replaced with your API key.
# Sign in to see your own test API key embedded in code samples.
# Don't put any keys in code. We recommend using a restricted API key with access only to the account sessions resource. See https://docs.stripe.com/keys-best-practices
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/account_session' do
  content_type 'application/json'

  # Create an AccountSession
  begin
    account_session = client.v1.account_sessions.create({
      account: {{CONNECTED_ACCOUNT_ID}},
      components: {
        account_onboarding: {
          enabled: true,
          features: {
            # We recommend disabling authentication for a better user experience when possible
            disable_stripe_user_authentication: true,
          }
        }
      }
    })

    {
      client_secret: account_session[:client_secret]
    }.to_json
  rescue => error
    puts "An error occurred when calling the Stripe API to create an account session: #{error.message}";
    return [500, { error: error.message }.to_json]
  end
end
```

### Create Account Session API

The [Create Account Session API](https://docs.stripe.com/api/account_sessions/create.md) determines component and feature access for Connect embedded components. Stripe enforces these parameters for any components that correspond to the account session. If your app supports multiple user roles, make sure components and features that are enabled for that account session correspond to the current user’s role. For example, you can enable [refund management](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-payments-features-refund_management) only for administrators of your site, but not for other users. To make sure user role access are enforced, you must map your site’s user role to account session components.

### Install the StripeConnect SDK (Client)

The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/).

To install the SDK, add `connect` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file:

#### Kotlin

```kotlin
plugins {
    id("com.android.application")
}

android { ... }

dependencies {
  // ...

  // Connect Android SDK
  implementation("com.stripe:connect:23.15.0")
}
```

> For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository).

### Initialize EmbeddedComponentManager  (Client)

Instantiate an [EmbeddedComponentManager](https://stripe.dev/stripe-android/connect/com.stripe.android.connect/-embedded-component-manager/index.html) with your publishable key and a lambda that retrieves a client secret by calling the new endpoint you created on your server. To handle configuration changes, keep the `EmbeddedComponentManager` instance in an Activity or Fragment `ViewModel`.

#### Kotlin

```kotlin
class MyActivityViewModel : ViewModel() {
    val embeddedComponentManager: EmbeddedComponentManager =
        EmbeddedComponentManager(
            // This is a placeholder - it should be replaced with your publishable API key.
            // Sign in to see your own test API key embedded in code samples.
            // Don't submit any personally identifiable information in requests made with this key.
            publishableKey = "<<YOUR_PUBLISHABLE_KEY>>",
            fetchClientSecret = ::fetchClientSecret,
        )

    private suspend fun fetchClientSecret(): String? =
        try {
            // Fetch the AccountSession client secret
            Fuel.post("https://{{YOUR_SERVER_BASE_URL}}/account_session")
                .awaitString()
                .let { JSONObject(it).getString("client_secret") }
        } catch (error: CancellationException) {
            throw error
        } catch (error: Exception) {
            // Handle errors on the client side here
            println("Error fetching client secret: ${error.message}")
            null
        }
}
```

To create a component, first call `EmbeddedComponentManager.onActivityCreate()` in your Activity’s `onCreate` method. Then, call the appropriate create method on the `EmbeddedComponentManager` that you instantiated above.

[Account onboarding](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) returns a controller which manages its own presentation. Other components, such as [Payments](https://docs.stripe.com/connect/supported-embedded-components/payments.md) returns a [View](https://developer.android.com/reference/android/view/View) that you can display in your app with more flexibility.

#### Rendering a controller

#### Kotlin

```kotlin
class MyActivity : FragmentActivity() {
    private val viewModel: MyActivityViewModel by viewModels()
    private lateinit var accountOnboardingController: AccountOnboardingController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        EmbeddedComponentManager.onActivityCreate(this)
        setContentView(R.layout.my_activity)

        accountOnboardingController =
            viewModel.embeddedComponentManager.createAccountOnboardingController(this)
    }

    private fun openAccountOnboarding() {
        accountOnboardingController.show()
    }
}
```

#### Rendering a `View`

#### Kotlin

```kotlin
class MyActivity : FragmentActivity() {
    private val viewModel: MyActivityViewModel by viewModels()
    private lateinit var paymentsView: View

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        EmbeddedComponentManager.onActivityCreate(this)
        setContentView(R.layout.my_activity)

        paymentsView = viewModel.embeddedComponentManager.createPaymentsView(this)

        // Add the view to your layout
        val container = findViewById<ViewGroup>(R.id.payments_container)
        container.addView(paymentsView)
    }
}
```

## Configure the Embedded Component Manager [Client-side]

[See the reference documentation :external:](https://stripe.dev/stripe-android/connect/com.stripe.android.connect/-embedded-component-manager/index.html).

### Customize the look of Connect embedded components

The [embedded components Figma UI toolkit](https://www.figma.com/community/file/1438614134095442934) contains every component, common patterns, and an example application. You can use it to visualize and design embedded UIs on your website.

We offer a [set of options](https://docs.stripe.com/connect/embedded-appearance-options.md) to customize the look and feel of Connect embedded components. These customizations affect buttons, icons, and other accents in our design system.

> #### Necessary popups
> 
> Some behavior in embedded components, such as [user authentication](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#user-authentication-in-connect-embedded-components), must be presented in an authenticated WebView. You can’t customize the embedded component to eliminate such WebViews.

You can set these options using [Appearance](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance/-appearance/index.html) when initializing `EmbeddedComponentManager`.

#### Kotlin

```kotlin
// Specify custom fonts
val customFonts = listOf(
    CustomFontSource(
        // Font file located in `assets/` folder
        assetsFilePath = "fonts/myCustomFont.ttf",
        name = "myCustomFont",
        weight = 1000,
    )
)

// Customize appearance
val appearance = Appearance.Builder()
    .typography(
        Typography.Builder()
            .fontFamily("myCustomFont") // Same name as the custom font above
            .fontSizeBase(16f) // Unscaled font size
            .build()
    )
    .colors(
        Colors.Builder()
            .primary(Color.RED)
            .build()
    )
    .build()

val embeddedComponentManager = EmbeddedComponentManager(
    publishableKey = "<<YOUR_PUBLISHABLE_KEY>>",
    fetchClientSecret = ::fetchClientSecret,
    appearance = appearance,
    customFonts = customFonts,
)
```

When specifying font sizes, use the unscaled font size that displays for the device’s default size class. The embedded component automatically scales the font size based on the user’s [Accessibility font settings](https://support.google.com/accessibility/android/answer/11183305?sjid=3094445894544346025-NA#fontsize).

 See the [full list of appearance options](https://docs.stripe.com/connect/embedded-appearance-options.md?platform=android) on Android.

### Use custom fonts 

If you use custom fonts in your app (for example, from `.otf` or `.tff` files embedded in your app binary), you must specify the font files in a [CustomFontSource](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance.fonts/-custom-font-source/index.html) passed to the `customFonts` argument when initializing `EmbeddedComponentManager`. This gives Connect embedded components access to the font files to properly render the fonts.

Fonts specified in `appearance` must use a [CustomFontSource](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance.fonts/-custom-font-source/index.html) passed to the `EmbeddedComponentManager` on initialization to properly render.

[See the reference documentation :external:](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance.fonts/-custom-font-source/index.html).

### Update Connect embedded components after initialization

Call the `update` method to change the appearance of the embedded components after initialization:

#### Kotlin

```kotlin
val appearance = Appearance.Builder()
    .colors(
        Colors.Builder()
            .primary(ContextCompat.getColor(context, R.color.primary))
            .build()
    )
    .build()
embeddedComponentManager.update(appearance = appearance)
```

## Authentication

We offer a set of APIs to manage account sessions and user credentials in Connect embedded components.

### Refresh the client secret

On long running sessions, the session from the initially provided *client secret* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components) might expire. When it expires, we automatically use `fetchClientSecret` to retrieve a new client secret and refresh the session. You don’t need to pass in any additional parameters.

#### Kotlin

```kotlin
val embeddedComponentManager: EmbeddedComponentManager =
    EmbeddedComponentManager(
        publishableKey = "<<YOUR_PUBLISHABLE_KEY>>",
        fetchClientSecret = ::fetchClientSecret,
    )

private suspend fun fetchClientSecret(): String? =
    try {
        Fuel.post("https://{{YOUR_SERVER_BASE_URL}}/account_session")
            .awaitString()
            .let { JSONObject(it).getString("client_secret") }
    } catch (error: CancellationException) {
        throw error
    } catch (error: Exception) {
        null
    }
```

## Localization

Connect embedded components support the following locales:

| Language | Locale code |
| --- | --- |
| Bulgarian (Bulgaria) | `bg-BG` |
| Chinese (Simplified) | `zh-Hans` |
| Chinese (Traditional - Hong Kong) | `zh-Hant-HK` |
| Chinese (Traditional - Taiwan) | `zh-Hant-TW` |
| Croatian (Croatia) | `hr-HR` |
| Czech (Czechia) | `cs-CZ` |
| Danish (Denmark) | `da-DK` |
| Dutch (Netherlands) | `nl-NL` |
| English (Australia) | `en-AU` |
| English (India) | `en-IN` |
| English (Ireland) | `en-IE` |
| English (New Zealand) | `en-NZ` |
| English (Singapore) | `en-SG` |
| English (United Kingdom) | `en-GB` |
| English (United States) | `en-US` |
| Estonian (Estonia) | `et-EE` |
| Filipino (Philippines) | `fil-PH` |
| Finnish (Finland) | `fi-FI` |
| French (Canada) | `fr-CA` |
| French (France) | `fr-FR` |
| German (Germany) | `de-DE` |
| Greek (Greece) | `el-GR` |
| Hungarian (Hungary) | `hu-HU` |
| Indonesian (Indonesia) | `id-ID` |
| Italian (Italy) | `it-IT` |
| Japanese (Japan) | `ja-JP` |
| Korean (South Korea) | `ko-KR` |
| Latvian (Latvia) | `lv-LV` |
| Lithuanian (Lithuania) | `lt-LT` |
| Malay (Malaysia) | `ms-MY` |
| Maltese (Malta) | `mt-MT` |
| Norwegian Bokmål (Norway) | `nb-NO` |
| Polish (Poland) | `pl-PL` |
| Portuguese (Brazil) | `pt-BR` |
| Portuguese (Portugal) | `pt-PT` |
| Romanian (Romania) | `ro-RO` |
| Slovak (Slovakia) | `sk-SK` |
| Slovenian (Slovenia) | `sl-SI` |
| Spanish (Argentina) | `es-AR` |
| Spanish (Brazil) | `es-BR` |
| Spanish (Latin America) | `es-419` |
| Spanish (Mexico) | `es-MX` |
| Spanish (Spain) | `es-ES` |
| Swedish (Sweden) | `sv-SE` |
| Thai (Thailand) | `th-TH` |
| Turkish (Türkiye) | `tr-TR` |
| Vietnamese (Vietnam) | `vi-VN` |

## User authentication in Connect embedded components

Connect embedded components typically don’t require user authentication. In some scenarios, Connect embedded components require the connected account to sign in with their Stripe account before accessing the component to provide the necessary functionality (for example, writing information to the account legal entity in the case of the [account onboarding](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) component). Other components might require authentication within the component after they initially render.

Authentication is required for connected accounts where Stripe is responsible for collecting updated information when requirements change. For connected accounts where you’re responsible for collecting updated information when requirements are due or change, such as Custom accounts, Stripe authentication is controlled by the [disable_stripe_user_authentication](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-account_onboarding-features-disable_stripe_user_authentication) Account Session feature. We recommend implementing 2FA or equivalent security measures as a [best practice](https://docs.stripe.com/connect/risk-management/best-practices.md#prevent-account-take-overs). For account configurations that support this feature, like Custom, you assume liability for connected accounts if they can’t pay back [negative balances](https://docs.stripe.com/connect/risk-management/best-practices.md#decide-your-approach-to-negative-balance-liability).

### Components requiring authentication

Connected accounts will be shown an authenticated [WebView](https://developer.chrome.com/docs/android/custom-tabs) within your application. The connected account must authenticate before they can continue their workflow within the WebView.

The Stripe-hosted authentication flow shows your brand’s name, color, and icon as set in your [Connect settings](https://dashboard.stripe.com/account/applications/settings) and doesn’t use your custom appearance and fonts from the [Embedded Component Manager](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#configuring-connect) until authentication completes.

> #### Android limitation
> 
> Due to a limitation within the Android APIs, embedded components can’t use custom fonts within the authenticated WebView, even after authentication completes.

The following component requires connected accounts to authenticate in certain scenarios:

- [Account Onboarding](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md)
- [Payouts](https://docs.stripe.com/connect/supported-embedded-components/payouts.md)

## Handle load errors [Client-side]

Respond to component load failures by implementing the component’s `onLoadError` listener method.

Different failure causes might call the `onLoadError` method multiple times, so any logic triggered by the `onLoadError` must be idempotent.

#### Kotlin

```kotlin
// All components emit load errors. This example uses AccountOnboarding.
// All components support onLoadError.
class MyActivity : FragmentActivity() {
    private lateinit var accountOnboardingController: AccountOnboardingController

    override fun onCreate(savedInstanceState: Bundle?) {
        accountOnboardingController =
            embeddedComponentManager.createAccountOnboardingController(this)
        accountOnboardingController.listener = MyAccountOnboardingListener()
    }

    private fun openAccountOnboarding() {
        accountOnboardingController.show()
    }

    private inner class MyAccountOnboardingListener : AccountOnboardingListener {
        override fun onLoadError(error: Throwable) {
            println("Error loading account onboarding: ${error.message}")
        }
    }
}
```
