React and Next.js
Use the shared installation checks. Keep the actual generated configuration; adapt the loader to the app's existing script lifecycle rather than pasting script tags into a component's returned markup.
Choose one lifecycle owner
For a persistent floating widget, mount one client-side owner in the shared app
shell/layout. Load the SDK once and initialize the widget once for that owner.
Separate SDK available from widget mounted: window.voiceflow can still
exist after destroy() or after an embedded target disappeared.
For page-owned embedded chat, initialize only after its target mounts and call
destroy() when that owner really unmounts. Dispose owned listeners. Prevent a
late script-load callback from initializing against an unmounted target. If a
new owner appears while loading, it must still be able to initialize. Do not
destroy a shared widget from a child page's cleanup.
React development Strict Mode deliberately repeats setup/cleanup. Exercise that cycle; do not turn Strict Mode off or use a permanent guard that suppresses the second mount after the first cleanup destroyed the widget. Avoid depending on a freshly allocated configuration object that retriggers setup every render.
Next.js
Use a Client Component for browser API access and script callbacks. A suitable
shared layout can include that component without becoming a client-only app.
next/script provides loading strategies; afterInteractive suits a readily
available launcher, while lazyOnload deliberately delays it. Respect the
existing site's choice rather than adding a second loader.
An inline Script needs a stable id. With an external script, remember that
onReady runs again on component mounts; SDK script deduplication does not
deduplicate chat.load() calls. A reused SDK still needs initialization after
an intentional widget teardown. Keep credentials out of public environment
variables and serialized props; only the generated browser verification belongs
in client code.
Customize and check
Keep brand overrides beside this one configuration; use customization for remote settings and supported CSS. A custom support button should invoke the existing ready widget, not mount another one.
Test a cold deep link, development remount, production build, route changes, Back, and a slow SDK load followed by navigation. Confirm one widget and expected conversation persistence. For authenticated sites, also check logout/account switch without leaking the previous conversation. Roll back the integration component and its imports/listeners, retaining unrelated layout code.
Sources: React effects, Next.js scripts.