Skip to content

In-App Forms: add lifecycle events for session ready and load failed/aborted #598

Description

@kodypeterson

Checklist

Description

registerForInAppForms() loads klaviyo.js into a WebView and waits on a one-shot handshake (the native bridge HandShook message). The current public FormLifecycleEvent only exposes formShown / formDismissed / formCtaClicked, all of which fire after a form is presented. There is no public signal for:

  • the forms session becoming ready (handshake completed, klaviyo.js loaded, listeners active), or
  • the session failing/aborting (e.g. the handshake timing out, which currently logs IAF WebView Aborted: Timeout waiting for Klaviyo.js and destroys the WebView).

formDismissed explicitly does not fire on internal teardowns/aborts, so today there is no way for host apps to observe whether In-App Forms are actually operational.

Motivation / use case

On real devices with a cold WebView cache and a slow network at launch, the handshake exceeds the timeout and the WebView is torn down with no retry and no observable signal. The form never appears for that session, and the app has no way to know it failed. We've had to implement blind, timed re-registration as a workaround precisely because the SDK exposes no success/failure signal to react to. A ready/failed callback would let integrators:

  1. Confirm forms are functioning (observability / analytics / health checks).
  2. Implement intelligent retry/backoff on failure instead of guessing.
  3. Stop retrying once ready fires, avoiding wasted work.

Proposed Solution

Extend FormLifecycleEvent (or add a separate session-lifecycle callback) with ready/failed cases carrying a reason:

// iOS
public enum FormLifecycleEvent: Equatable, Sendable {
    // ...existing formShown / formDismissed / formCtaClicked...
    case formsSessionReady
    case formsSessionFailed(reason: FormsFailureReason)
}
public enum FormsFailureReason: Equatable, Sendable { case handshakeTimeout, networkError, webViewUnsupported, renderProcessGone, unknown }

Additional Context

  • Versions: Android 4.4.0, iOS 5.3.1 (latest at time of filing).
  • Today the only evidence of a failed load is an internal log line (IAF WebView Aborted: Timeout waiting for Klaviyo.js), available only via Logcat/Console with verbose logging — not consumable in code.
  • Related: a built-in retry on the handshake would reduce the need for this, but a failed signal is still valuable for observability even if retry is added.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions