- the cookie probe, and the fallback to a window or a redirect
- the one-launch-at-a-time guard
resume()
The launch URL
embed names the context the flow is opened in: iframe for a frame on your page, popup for a window you open, redirect for the current tab.
Set the parameters on the invitation URL, which keeps whatever it already carries. Invitation URLs already have a query string (?invite=…, or ?tms_invite=… for a TMS invitation), so add the parameters to it rather than starting a second one. In script, URL.searchParams does that for you, and it also encodes a leading # in brand_color and brand_secondary:
https, except on localhost, 127.0.0.1 and [::1], for the reasons the inviteUrl option gives. The flow ignores parameters it does not recognize.
The Presentation options section describes what the six optional parameters do, and the same rules hold here:
- The flow validates the values.
- An invalid value falls back to its default on its own.
- The four branding parameters apply only when the embed key resolves.
A plain iframe, link or window
The HTML examples usehttps://connect.example.com/?invite=YOUR_INVITE_ID where your invitation URL goes, with the parameters joined to its query string by &. The script examples use inviteUrl and the launchUrl() helper from The launch URL.
A frame
A frame on your page, withembed=iframe. It needs no allow attribute, because the flow uses nothing a cross-origin frame is denied by default:
sandbox. The flow opens its own window for some providers’ sign-in, and a sandbox without allow-popups blocks it.
A link
A link, or a navigation, withembed=redirect. The flow runs in the tab. If your invitation has a success and a failure URL, the flow returns to one of them, and that is where you learn the outcome. Without them, the flow ends on its last screen and your webhooks are the record. See The redirect path.
A window
A window, withembed=popup, opened under the name catena-connect and without noopener. noopener would sever the channel the messages travel on.
Reusing the name catena-connect lands a second window.open() on the first window, but reloads it and restarts the flow. To bring an open window back, check popup.closed and call popup.focus() instead.
window.open() synchronously inside the click handler. An await between the click and the call spends the activation, and the browser blocks the window. window.open() returns null when the browser refused, and some blockers return a window that is already closed. The package treats both as blocked and navigates the tab with embed=redirect, and the example does the same.
With no listener at all, your connection webhooks tell you the outcome, and on the redirect path so does the page the flow returns to, if your invitation has redirect URLs. For many sites that is a complete integration.
Reading the completion messages
A frame or a window posts a message to the page that opened it when the flow is ready, as each provider is connected or a connection is deleted, and when the user finishes. Every message has this shape, with the detail besideevent and no wrapper around it:
exit reasons for an invite link that never loaded. The flow posts close straight after success or exit, never on its own. A user who closes your window produces nothing. If the surface stays up the user can press the button again, and the outcome and close are posted again. The package keeps only the first outcome, so a plain listener should too.
open can arrive more than once, for example after the embedded page reloads, so make its handler safe to run twice.
Check three things before you trust a message, on every message:
event.originis the connect origin, the origin of your invitation URL.event.sourceis the frame or window you opened.event.data.sourceis"catena-connect".
event.source with what window.open() returned.
The listener does not check version, for the same reason the package does not: it handles the events it recognizes in any version, so a version bump cannot silence it.
open is the flow’s own message and reaches a registered origin only, so receiving it is also the sign your origin is registered, as it is for onOpen with the package.
Ignore events, versions and fields you do not recognize. Additions arrive in minor releases, and Versioning and support says what is promised to stay.
Which events arrive depends on how the URL was opened:
What a plain integration gives up
- No cookie probe and no fallback. The package checks whether the browser will send the flow’s cookie in a frame, and falls back to a window or a redirect when it will not. A plain frame in a browser that refuses third-party cookies shows the flow failing to sign in instead. If you cannot vouch for the browsers, open a window with
embed=popupor navigate the tab withembed=redirect. - No single-launch guard. Two frames run two flows. Opening a window under the name
catena-connecteach time lands a secondwindow.open()on the first window, but reloads it and restarts the flow. - No de-duplication of the outcome. The outcome and
closecan be posted more than once. Keep the first outcome yourself. - No teardown of the window. The package closes it on
destroy(). You close your own. - No
resume(). Which destination page was reached says how the flow ended, and your webhooks carry the detail, as they do on the package’s redirect path. Without a record written before the navigation, though, a destination page cannot tell a return from the flow apart from a direct visit. - No shadow-root surface. You style and position the frame or the window, and you decide when to take it down.
embed value and the opening method yourself.