• Home
  • Features
  • Spec
  • Guides
  • Sandbox
  • Overview
  • Quick start
    • Integrating on Web
    • Integrating on iOS
    • Integrating on Android
  • Writing or editing a flow
  • Working with custom renderers
  • Analytics

Integrating on Web

This page is for Web engineers who want to integrate an existing flow into their product.

These instructions presume you’re using React.

Install required dependencies (including Neptune UI dependencies)

Install react, the design system component and styling packages, and the Dynamic Flow client.

# pnpm
pnpm add react react-dom react-intl
pnpm add @transferwise/components @transferwise/icons @transferwise/neptune-css @wise/components-theming @wise/art @transferwise/formatting
pnpm add @wise/dynamic-flow-client-internal

If you're using TypeScript, you might also want to install the types package, which contains:

  • Types for all Dynamic Flow entities (useful when using initialStep, or for writing mocks)
  • Zod validators
  • Renderer Props, for writing custom renderers
pnpm add -D @wise/dynamic-flow-types

Set up your app using Neptune UI

To get Dynamic Flow working, you’ll need to import the correct CSS files, prepare the translations using the user’s locale, and wrap the component in several providers.

For CRAB apps, use the getLocalisedMessages(...) function for translations

import "@transferwise/neptune-css/dist/css/neptune.css";
import "@transferwise/components/build/main.css";
import '@transferwise/icons/lib/styles/main.min.css';
import "@wise/dynamic-flow-client-internal/build/main.css";

import {
  Provider,
  SnackbarProvider,
  translations as componentTranslations,
} from '@transferwise/components';
import { getLocalisedMessages } from '@transferwise/crab/client';
import { ThemeProvider } from "@wise/components-theming";
import { DynamicFlow, translations as dynamicFlowsTranslations } from '@wise/dynamic-flow-client-internal';

const App = () => {
    const messages = getLocalisedMessages(locale, [componentTranslations, dynamicFlowsTranslations])

    return (
      <Provider i18n={{ locale, messages }}>
        <ThemeProvider theme={theme} screenMode={screenMode}>
          <SnackbarProvider>
            <DynamicFlow {...props} />
          </SnackbarProvider>
        </ThemeProvider>
      </Provider>
    );
}

export default App;

For non-CRAB apps

You'll need to merge the '@transferwise/components' translations with the '@wise/dynamic-flow-client' translations.

import "@transferwise/neptune-css/dist/css/neptune.css";
import "@transferwise/components/build/main.css";
import '@transferwise/icons/lib/styles/main.min.css';
import "@wise/dynamic-flow-client-internal/build/main.css";
import {
  Provider,
  SnackbarProvider,
  translations as componentTranslations,
} from '@transferwise/components';
import {
  DynamicFlow,
  translations as dynamicFlowTranslations,
} from '@wise/dynamic-flow-client-internal';
import { ThemeProvider } from "@wise/components-theming";

const App = () => {
  // create your messages object
  const messages: Record<string, string> = {
    ...(componentTranslations[lang] || componentTranslations[lang.replace('-', '_')] || componentTranslations[lang.substring(0, 2)] || {}),
    ...(dynamicFlowTranslations[lang] || dynamicFlowTranslations[lang.replace('-', '_')] || dynamicFlowTranslations[lang.substring(0, 2)] || {}),
  }

  return (
    <Provider i18n={{ locale, messages }}>
      <ThemeProvider theme={theme} screenMode={screenMode}>
        <SnackbarProvider>
           <DynamicFlow {...props} />
        </SnackbarProvider>
      </ThemeProvider>
    </Provider>
  );
}

export default App;

Initialise the Dynamic Flow client

<DynamicFlow
  flowId="my-flow"
  customFetch={fetch}
  initialAction={initialAction}
  onComplete={(status, data) => console.log(status, data)}
/>

Dynamic Flow client props

PropsRequiredDescription
flowIdYesFlow id used in events.
customFetchYesCustom fetch function that may add authentication headers to every request.
initialActionYes*Initial Action to execute to get the first step. *Not required if using initialStep.
initialStepYes*Initial Step. *Not required if using initialAction.
renderersNoA list of renderers to customise presentation with. See the custom rendering guide.
onAnalytics NoCallback that accepts eventName and possible data object.
onCompleteYesCallback that accepts a status and possible data object.
onErrorNoCallback that accepts an error and possible status object.
onEventNoCallback that accepts eventName and possible data object.

Please, check the README.md.

Custom Rendering on Web

You can provide additional renderers to utilise custom rendering. It is important that these are statically defined, or the component might be re-rendered continuously.

For example, instead of doing this:

<DynamicFlow
  flowId="my-flow"
  customFetch={fetch}
  initialAction={initialAction}
  renderers={[MyCustomRenderer]}   // <-- ❌ Not statically defined, will create a new reference on every render
  onComplete={(status, data) => console.log(status, data)}
/>

Do this:

const renderers = [MyCustomRenderer]; // <-- ✅ Statically defined, reference is stable across renders

const WrappingComponent = () => {

    return (
        <DynamicFlow
          flowId="my-flow"
          customFetch={fetch}
          initialAction={initialAction}
          renderers={renderers}
          onComplete={(status, data) => console.log(status, data)}
        />
    );
}