Skip to main content
Each entry starts with what you see on the page. The cause and the fix follow, and the link at the end goes to the section that explains the mechanism. Symptoms the React wrapper can cause on its own, such as two surfaces on the page or an overlay left behind, are on the React page.

Symptoms

You see a Continue button where the flow should be.Cause. The package could not confirm that this browser will run the flow in a frame. The possible reasons:
  • The launching page’s origin is not registered against your embed key, or the key is unknown or revoked. The console shows a frame-ancestors violation.
  • The browser refused the flow’s cookie in a frame.
  • Your page’s Content Security Policy blocks the connect origin from being framed.
  • The probe frame never answered in time: a blocked request, a frame that never loaded, or a slow network.
  • The check passed, but the flow’s iframe loaded and never reported it was ready, usually because the connect origin refused to be framed. The button appears about eight seconds after that iframe loads.
  • This page already probed once with no answer. The verdict is kept until the page reloads.
The flow still works through the button. It opens the flow in a window, or in the tab when the browser blocks the window too and your page is not itself framed (see the next entry). On an unregistered origin or with an unknown key, though, the window posts nothing to your page.Fix. When the origin is the cause, register the exact origin: scheme, host and port must match, and www and the apex are different origins. Registered origins must be https, or http on localhost.When the policy is the cause, allow the origin of your invitation URL in frame-src. If your policy has no frame-src, use child-src, and if it has neither, use default-src. The cookie probe is a frame on the same origin and falls under the same directive. The package makes no requests of its own, so no other directive needs to change.A refused cookie decides within one round trip. A probe frame that loads and never answers, including on an unregistered origin, waits about six seconds after it loads before the button appears, and one that never loads at all waits up to eight. The flow’s own iframe waits eight seconds after it loads, as in the last cause above. Only the policy and origin cases show in the browser console, as a violation report. A refused cookie or an unanswered frame on a registered origin leaves nothing there.See the three modes.
You click Continue and the whole tab leaves your page.Cause. The browser blocked the window too, so the flow continued in the tab. This is the third mode, working as designed. A page inside a frame is never navigated this way: the surface asks the user to allow pop-ups and press Continue again instead.Fix. Allow popups on the launching page. If your invitation has redirect URLs, make sure both pages call resume(). Without them, the flow ends on its last screen and your webhooks are the record.See the three modes and resume().
The flow shows a message saying the sign-in window was blocked.Cause. Popups are not allowed on the launching page. The flow stays up with the form intact, and nothing fires until the setting allows the window.Fix. Allow popups on the launching page.See the provider window.
The flow runs, but none of your callbacks fire.Cause. Most often the launching page’s origin is not registered against your embed key, or the key is unknown or revoked. The two look the same from your page. The flow falls back to the popup and runs there, but its messages are addressed elsewhere, or for an unknown or revoked key not sent at all. The other causes:
  • A window or link you opened yourself used noopener. The package never opens with noopener.
  • The launching page sends Cross-Origin-Opener-Policy: same-origin, which severs the popup.
  • The flow ran in the tab and no page called resume().
  • The destination page is on another origin.
  • The user left.
Fix. Check each case in When you receive nothing. Your webhooks are the record in every case.
You press Continue, the popup opens, and onClose arrives straight away with no outcome. The user carries on in the window.Cause. The launching page sends Cross-Origin-Opener-Policy: same-origin, which disconnects it from the popup as soon as the popup loads the flow. From your page the window looks closed. The console shows a warning from the package naming the header.Fix. Serve the launching page with same-origin-allow-popups instead. It keeps the popup connected and changes nothing else.See When you receive nothing.
The flow appears and onExit arrives at once, followed by onClose, with reason set to invalid_invitation or invitation_unavailable.Cause. The flow could not load the invitation in the link. Behind the callbacks the flow shows an error screen, which goes away when you take the surface down on onClose.Fix. For invalid_invitation, check the invitation you launched with and create a new link. For invitation_unavailable, offer a retry, since the link may be fine. Show the user your own message either way.See onExit when the invite link never loaded.
Calling open() throws an error and nothing renders.Cause. open() throws a TypeError if the invitation URL does not parse, is not http or https, or is http on any host other than localhost, 127.0.0.1 or [::1]. It also throws if it is called before <body> exists with no container, or outside a browser.Fix. Pass an https invitation URL. Plain http is accepted on localhost, 127.0.0.1 and [::1] only. Call open() in a browser, after <body> exists or with a container.See open().
A resume() callback fires on a page the user reached some other way.Cause. A redirected launch left this tab within the last 30 minutes and was abandoned, and resume() consumed its record.Fix. Call resume() on the two destination pages and nowhere else.See resume() and When you receive nothing.
The flow appears with your account’s branding instead of the color or logos you passed.Cause. One of these:
  • The embed key does not resolve to a registered, active key. brandColor, brandSecondary, logoUrl and logoUrlDark are dropped and the branding configured on your account applies.
  • A value was rejected. brandColor and brandSecondary must contain exactly six hex digits, with an optional leading #, and logo URLs must be absolute https.
  • A logo failed to load. That leaves its slot empty.
  • You passed variant: "card". The logo then shows only on the consent card.
Fix. Use an embed key that is registered and active, and check each value against the rules.See presentation options, which explains why branding needs your embed key to resolve.
Calling open() again does not start a new flow.Cause. One flow runs at a time. The call brought the live launch back and returned its handle: the popup window if one is open, otherwise the overlay. In a container it does nothing visible.Fix. Let the live flow end, or call destroy() on its handle, before launching again.See one flow at a time.

When you receive nothing

Each of these is a real outcome, not an error to surface. Your connection webhooks remain the record. The absence of a callback is never proof that nothing happened.
  1. Unregistered origin. The page you embed from is not registered against your embed key. The flow falls back to the popup and runs, but every message is addressed elsewhere and the browser drops it. This is the origin check doing its job.
  2. Unknown or revoked embed key. This is deliberately indistinguishable from an unregistered origin. The flow falls back to the popup and runs, and sends no messages at all. You cannot tell the two apart, and neither can an attacker.
  3. Severed opener. Opening the flow through a window or link of your own with noopener removes the channel the completion travels on. The user still finishes. The package never opens with noopener.
  4. Cross-Origin-Opener-Policy: same-origin on the launching page. In the popup mode, the browser cuts your page off from the window as soon as it loads the flow. From your page the window looks closed, so you get onClose with no outcome shortly after the click, while the user carries on in a window your page cannot hear or close. If your invitation has redirect URLs, the flow then finishes by sending that window to one of them. Without them it stays on its last screen. The package logs a console warning when a window closes this fast. Serve the page with same-origin-allow-popups instead.
  5. Redirect mode with no resume() call. The flow completed in your tab and nothing was listening when it came back.
  6. A resume() destination on another origin. The outcome crosses the navigation in a sessionStorage record, and that is partitioned by origin as well as by tab. Both destination pages must be on the same origin as the page that launched, or resume() emits nothing.
  7. The user abandoned the surface. No terminal event was produced because the flow never reached one. In a frame, a user who connects and never presses Done produces onConnection but no onSuccess. The connection is real.
One caveat in the other direction: a callback means a redirected launch left this tab recently, not that this page was reached from the flow. An abandoned launch stays recorded for up to 30 minutes, and a resume() inside that window will consume it. Put the call on your two destination pages and nowhere else.