@replit/connect
v1.7.1
Published
Frontend SDK for embedding OpenInt's connection flow in host apps via popup, iframe (inline or dialog), or direct rendering — usable from Vanilla JS and React. Not the server-side connector framework or the consumer-side identity/proxy SDK; see `kits/cdk`
Maintainers
Keywords
Readme
OpenInt Connect (@openint/connect, published as @replit/connect)
Frontend SDK for embedding OpenInt's connection flow in host apps via popup, iframe (inline or dialog), or direct rendering — usable from Vanilla JS and React. Not the server-side connector framework or the consumer-side identity/proxy SDK; see kits/cdk (authoring connectors) and kits/connectors-sdk (calling OpenInt from Repls).
Methods of integration
- Remote rendering (More versatile, more secure)
- popup window
- iframe
- Inline
- As dialog
- Direct rendering (Faster, more integrated)
In addition, should be usable from
- Vanilla JS
- React
React iframe
ConnectEmbed displays the hosted OpenInt Connect page in an iframe. OpenInt
creates or updates the connection and forwards OpenInt events to the host.
The host application updates its own state after the flow completes.
By default, every parent render replaces the iframe, preserving the behavior
of earlier SDK versions. Set preserveIframeOnRerender={true} to opt in to the
stable lifecycle: unrelated rerenders, new callback identities, and equivalent
freshly allocated connectOptions preserve the iframe and its OAuth flow.
Events then use the latest committed onEvent callback. A changed serialized
Connect URL (including token or options), apiBaseURL, dimensions, or
adding/removing onEvent still recreates the iframe and stops the old listeners.
The option is a React component prop, not a hosted connectOptions setting.
The SDK does not evaluate feature flags. Hosts using a rollout gate must capture
its value at the start of an attempt and keep it fixed until that attempt ends.
Turning the gate off restores legacy behavior for subsequent attempts, including
the known rerender race; it must not interrupt an active flow.
Omit baseURL to use the SDK default. When you set it, use an OpenInt Connect
page URL that ends exactly in /connect. Do not use an API URL or a trailing
slash. Generate a unique conn_<uuid> flow ID for each connection attempt.
The event feed is not scoped to an embed. Handle only terminal events with a
matching flow_id. The unsubscribe callback stops every poller for the current
embed. Call it before host code when the flow completes or polling stops.
Event polling normally uses the same host as baseURL, replacing its /connect
suffix with /api/v1. Set the optional apiBaseURL to route polling through a
different API host or a same-origin forwarder, for example
apiBaseURL="https://your-app.example/__openint/api/v1". Include the full API
base path; a trailing slash is optional. This does not change the iframe URL,
token, polling interval, or event handling.
import type {ComponentProps} from 'react'
import {ConnectEmbed} from '@replit/connect'
import {useCallback} from 'react'
type ConnectEventHandler = NonNullable<
ComponentProps<typeof ConnectEmbed>['onEvent']
>
type FlowEvent = {connectionId: string; flowId: string}
function getFlowEvent(event: {data: unknown; name: string}): FlowEvent | null {
if (!event.data || typeof event.data !== 'object') return null
const data = event.data as {connection_id?: unknown; flow_id?: unknown}
if (typeof data.flow_id !== 'string') return null
switch (event.name) {
case 'connect.connection-connected':
return typeof data.connection_id === 'string'
? {connectionId: data.connection_id, flowId: data.flow_id}
: null
default:
return null
}
}
function AddConnection({
flowId,
onConnected,
onPollingError,
token,
}: {
flowId: string
token: string
onConnected: (connectionId: string) => void
onPollingError: () => void
}) {
const handleEvent = useCallback<ConnectEventHandler>(
(event, unsubscribe) => {
if (event.name === 'connect.loading-error') {
unsubscribe()
onPollingError()
return
}
const flowEvent = getFlowEvent(event)
if (!flowEvent || flowEvent.flowId !== flowId) return
unsubscribe()
onConnected(flowEvent.connectionId)
},
[flowId, onConnected, onPollingError],
)
return (
<ConnectEmbed
token={token}
baseURL="https://connectors.replit.com/connect"
connectOptions={{flowId, hideNavigation: true, view: 'add'}}
onEvent={handleEvent}
height={700}
/>
)
}After iframe load, the SDK emits a synthetic connect.loaded event. It then
polls OpenInt for events. connect.loaded means the iframe loaded, not that
connection setup completed. With the preservation option enabled, updating
parent state preserves the iframe when its lifecycle inputs are unchanged.
Without it, a parent update replaces the iframe and can create a reload loop.
Unmount the component when the host cancels the flow. ConnectEmbed stops its
listener on unmount.
connect.connection-failed is best-effort analytics, not a complete iframe
failure callback. The iframe remains open for retry after this event, so the
sample keeps listening. The host must use its own UI and cancellation path for
all failure handling.
connect.loading-error reports that this listener stopped polling after three
request errors, so the sample reports that condition through onPollingError.
connect.connection-connected confirms connection creation. A requested
replId assignment has no completion event in this SDK. When assignment is
required, use and await a product-specific assignment operation after the
connection completes.
Avoid changing connection settings while a flow is active: those changes intentionally replace the iframe and restart event polling.
Release Process
Ensure to increment the version in package.json and run the following commands:
pnpm clean && pnpm build && pnpm pub