Embedded Stripe Apps
Embedded Stripe Apps allow platforms built on Stripe Connect to surface third-party app functionality directly within their own dashboards. Using Connect embedded components, you can give your connected accounts access to apps like QuickBooks, Xero, and Mailchimp without them needing to visit the Stripe Dashboard.
Overview
Embedded apps use two key Connect embedded components:
app-install: Renders an install button for a Stripe App within your platform UIapp-viewport: Renders a specific app viewport within your platform UI
This enables platform operators to embed accounting, marketing, and operational tools directly in their product.
Supported Apps
The following apps support embedding via Connect components:
| App | Category | Use Case |
|---|---|---|
| QuickBooks | Accounting | Sync payments and invoices to QuickBooks |
| Xero | Accounting | Automated bookkeeping and reconciliation |
| Mailchimp | Marketing | Sync customer data for email campaigns |
| Custom Apps | Any | Your own Stripe Apps built for your platform |
Tip
The Tajo Brevo integration can be embedded in Connect platforms, allowing connected accounts to sync their Stripe data to Brevo through the platform’s own interface.
Setup with Account Sessions API
To embed apps, you need to create Account Sessions with the appropriate components enabled:
Server-Side: Create Account Session
const stripe = require('stripe')('sk_live_...');
// Create an Account Session for the connected accountconst accountSession = await stripe.accountSessions.create({ account: 'acct_connected_account_id', components: { // Enable app install component app_install: { enabled: true, features: { allowed_apps: [ 'com.tajo.brevo-integration', 'com.quickbooks.stripe-app' ], }, }, // Enable app viewport component app_viewport: { enabled: true, features: { allowed_apps: [ 'com.tajo.brevo-integration' ], }, }, },});
// Return the client secret to your frontendres.json({ clientSecret: accountSession.client_secret });Client-Side: Initialize Connect.js
import { loadConnectAndInitialize } from '@stripe/connect-js';
// Initialize Connect.js with the account sessionconst stripeConnect = loadConnectAndInitialize({ publishableKey: 'pk_live_...', fetchClientSecret: async () => { const response = await fetch('/api/account-session', { method: 'POST', }); const { clientSecret } = await response.json(); return clientSecret; },});App Install Component
The app-install component renders an install button that connected accounts can use to install a Stripe App:
JavaScript
// Create the app install elementconst appInstall = stripeConnect.create('app-install');
// Set the app to installappInstall.setApp('com.tajo.brevo-integration');
// Mount to a DOM elementconst container = document.getElementById('app-install-container');appInstall.mount(container);
// Listen for install eventsappInstall.on('app_installed', (event) => { console.log('App installed:', event.app_id); // Show the app viewport after installation showAppViewport();});
appInstall.on('app_uninstalled', (event) => { console.log('App uninstalled:', event.app_id);});React
import { ConnectAppInstall, ConnectComponentsProvider,} from '@stripe/react-connect-js';
const AppInstallButton = () => { return ( <ConnectComponentsProvider connectInstance={stripeConnect}> <ConnectAppInstall app="com.tajo.brevo-integration" onAppInstalled={(event) => { console.log('App installed:', event.app_id); }} onAppUninstalled={(event) => { console.log('App uninstalled:', event.app_id); }} /> </ConnectComponentsProvider> );};App Viewport Component
The app-viewport component renders a specific app viewport within your platform:
JavaScript
// Create the app viewport elementconst appViewport = stripeConnect.create('app-viewport');
// Configure the viewportappViewport.setApp('com.tajo.brevo-integration');appViewport.setViewport('stripe.dashboard.customer.detail');
// Pass object context (e.g., customer ID)appViewport.setObjectContext({ id: 'cus_xxxxx', object: 'customer',});
// Mount to a DOM elementconst container = document.getElementById('app-viewport-container');appViewport.mount(container);React
import { ConnectAppViewport, ConnectComponentsProvider,} from '@stripe/react-connect-js';
const BrevoCusomerView = ({ customerId }: { customerId: string }) => { return ( <ConnectComponentsProvider connectInstance={stripeConnect}> <ConnectAppViewport app="com.tajo.brevo-integration" viewport="stripe.dashboard.customer.detail" objectContext={{ id: customerId, object: 'customer', }} /> </ConnectComponentsProvider> );};Destination Charge Metadata Schema
When using embedded apps with destination charges (common in Connect platforms), the charge metadata carries structured data that accounting and marketing integrations can consume.
Accounting Integrations
For apps like QuickBooks and Xero, destination charge metadata follows this schema:
{ "metadata": { "customer_id": "cus_platform_customer_id", "product_name": "Premium Subscription", "product_id": "prod_xxxxx", "quantity": "1", "unit_amount": "4999", "currency": "usd", "platform_fee": "500", "platform_fee_currency": "usd", "tax_amount": "450", "tax_rate_id": "txr_xxxxx", "invoice_id": "inv_xxxxx", "order_id": "order_12345" }}| Field | Type | Description |
|---|---|---|
customer_id | string | Platform’s customer identifier |
customer_email | string | Customer email for invoice/receipt matching |
product_name | string | Product display name for line items |
product_id | string | Stripe product ID |
quantity | string | Item quantity |
unit_amount | string | Unit price in smallest currency unit (cents) |
currency | string | Three-letter ISO currency code |
platform_fee | string | Application fee amount in smallest currency unit |
platform_fee_currency | string | Currency for the platform fee |
tax_amount | string | Tax amount in smallest currency unit |
tax_rate_id | string | Stripe tax rate ID applied |
invoice_id | string | Associated invoice ID |
order_id | string | Platform’s internal order identifier |
Marketing Integrations
For apps like Mailchimp and the Tajo Brevo integration, the metadata enables customer segmentation and campaign targeting:
{ "metadata": { "customer_id": "cus_xxxxx", "customer_name": "Jane Smith", "product_category": "subscription", "product_name": "Pro Plan", "purchase_value": "4999", "currency": "usd", "is_first_purchase": "true", "referral_source": "partner_campaign", "subscription_interval": "monthly", "lifetime_value": "29994" }}This metadata enables Brevo automations such as:
- Welcome series for first-time buyers (
is_first_purchase: "true") - Upsell campaigns based on
product_categoryandpurchase_value - Retention flows for subscription customers based on
subscription_interval - Win-back campaigns targeting high
lifetime_valuecustomers who churn
Platform Integration Example
A complete platform integration embedding the Tajo Brevo app:
import { useState, useEffect } from 'react';import { ConnectAppInstall, ConnectAppViewport, ConnectComponentsProvider,} from '@stripe/react-connect-js';import { loadConnectAndInitialize } from '@stripe/connect-js';
const TajoBrevoPlatformIntegration = ({ connectedAccountId, customerId }) => { const [stripeConnect, setStripeConnect] = useState(null); const [isInstalled, setIsInstalled] = useState(false);
useEffect(() => { const instance = loadConnectAndInitialize({ publishableKey: 'pk_live_...', fetchClientSecret: async () => { const res = await fetch('/api/account-session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ accountId: connectedAccountId }), }); const { clientSecret } = await res.json(); return clientSecret; }, }); setStripeConnect(instance); }, [connectedAccountId]);
if (!stripeConnect) return <div>Loading...</div>;
return ( <ConnectComponentsProvider connectInstance={stripeConnect}> {!isInstalled ? ( <div> <h3>Connect Brevo via Tajo</h3> <p>Install the Tajo integration to sync customer data with Brevo.</p> <ConnectAppInstall app="com.tajo.brevo-integration" onAppInstalled={() => setIsInstalled(true)} /> </div> ) : ( <div> <h3>Brevo Customer Profile</h3> <ConnectAppViewport app="com.tajo.brevo-integration" viewport="stripe.dashboard.customer.detail" objectContext={{ id: customerId, object: 'customer', }} /> </div> )} </ConnectComponentsProvider> );};Security Considerations
When embedding apps in your platform:
- Account Sessions expire: Create new sessions as needed; do not cache client secrets
- Scope control: Use
allowed_appsto restrict which apps can be installed - Data isolation: Each connected account’s data is isolated; the platform cannot access app data
- CSP headers: Ensure your platform’s Content Security Policy allows connections to
https://connect-js.stripe.com
Caution
Embedded app components require a Connect integration with Account Sessions API access. Standard Stripe accounts cannot use embedded components.