Skip to content

Embed the Connector Widget

Use this guide when you need to let a user connect their store to Conflux from inside your own page — for example, inside a Rapidmail account page or an onboarding screen — without requiring them to visit the Conflux admin panel.

The connector widget (<conflux-connector>) handles the full connection lifecycle: it auto-creates a tenant on first load, lets the user generate a plugin pairing token, and emits events you can react to on the host page.

1. Load the widget script

Add the script tag before the custom element is used:

<script src="https://your-conflux-domain.com/connector-widget.js" defer></script>

The script is a self-contained IIFE bundle with no external runtime dependencies. It registers the <conflux-connector> custom element and isolates its styles inside a shadow DOM, so it cannot be broken by the host page's CSS.

2. Place the element

Drop the element where the connection UI should appear:

<conflux-connector
    system="rapidmail"
    connection="woocommerce"
    external-user-id="user_12345"
    api-base="https://your-conflux-domain.com"
></conflux-connector>

On mount the widget calls POST /api/system-connections/connect to create a tenant and an active Rapidmail connection. The conflux-initialized event fires once that completes.

Props

Prop Required Description
system No Slug of the embedding system (e.g. rapidmail). When supplied and the slug matches a known System record in Conflux, the widget creates an Active connection immediately and issues a never-expiring access token instead of a short-lived pairing token.
connection No Slug of the target e-commerce system (e.g. woocommerce). Controls the plugin installation steps shown to the user and the system badge colour in the header.
external-user-id No User identifier in the embedding platform (e.g. a Rapidmail account ID). Stored on the SystemConnection for later matching.
api-base No Base URL of the Conflux instance (e.g. https://conflux.example.com). Defaults to empty string (same-origin). Always set this when embedding on an external domain.
tenant-id No UUID of an existing tenant. Pass this on subsequent page loads (after conflux-initialized has fired once) to skip the auto-creation step.
token No Plaintext access token issued on a prior init. Pass alongside tenant-id on subsequent loads to skip the init API call entirely.
lang No BCP 47 language tag (e.g. en). Reserved for future i18n support; has no effect in the current build.

Events

conflux-initialized

Fires once when the widget has created (or confirmed) a tenant and an Active connection to the embedding system (end of phase 1).

window.addEventListener('conflux-initialized', function (event) {
    const { tenant_id, token } = event.detail;
    // Persist both values server-side, keyed to the current user.
    // Pass them back as the tenant-id and token props on subsequent loads
    // so the widget skips the init step.
    myApi.saveConfluxCredentials(tenant_id, token);
});

Detail shape:

{
    "tenant_id": "018e1f2a-...",
    "token": "plaintext-access-token"
}

Store both values against the user's account. The token is the never-expiring access token issued by Conflux; it is returned only once. On subsequent page loads, pass tenant-id and token as props so the widget can skip the init call.

conflux-registered

Fires when the user's e-commerce plugin confirms the connection — that is, when Conflux detects that the pending SystemConnection has transitioned to active.

window.addEventListener('conflux-registered', function (event) {
    const { connection_id } = event.detail;
    console.log('Plugin connected:', connection_id);
    // Enable sync features for this user.
});

Detail shape:

{
    "connection_id": "018e1f2b-..."
}

Both events bubble through the shadow DOM boundary (bubbles: true, composed: true), so a single listener on window (or any ancestor element) can receive them regardless of where the widget is placed. They are dispatched from the <conflux-connector> host element itself, so attaching a listener directly to the element also works.

Full example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Connect your store</title>
</head>
<body>

    <conflux-connector
        system="rapidmail"
        connection="woocommerce"
        external-user-id="<?= esc_attr($currentUser->id) ?>"
        api-base="https://conflux.example.com"
    ></conflux-connector>

    <script src="https://conflux.example.com/connector-widget.js" defer></script>
    <script>
        window.addEventListener('conflux-initialized', function (event) {
            fetch('/my-app/api/conflux-credentials', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(event.detail),
            });
        });

        window.addEventListener('conflux-registered', function (event) {
            document.getElementById('sync-panel').hidden = false;
        });
    </script>

</body>
</html>

Returning users

On first load, emit conflux-initialized and persist tenant_id and token. On all subsequent loads, pass them back so the widget skips the init call:

<!-- Subsequent loads — pass credentials stored from the first visit -->
<conflux-connector
    system="rapidmail"
    connection="woocommerce"
    external-user-id="user_12345"
    tenant-id="{{ $user->conflux_tenant_id }}"
    token="{{ $user->conflux_token }}"
    api-base="https://conflux.example.com"
></conflux-connector>

When both tenant-id and token are present, the widget skips the init call and goes directly to the connection step.

Building the widget

The widget is pre-built and committed to public/connector-widget.js. You only need to rebuild when you change a source file under resources/widget-connector/ (including plugin-urls.js):

docker compose run --rm -T node npm run build:connector-widget

The bundle is an IIFE with no external runtime dependencies and does not include Vue as a separate chunk.

Troubleshooting

The widget shows "Could not reach the Conflux server." A network or CORS error prevented the init request. Confirm api-base is correct and that the Conflux instance allows cross-origin requests from your domain.

conflux-initialized fires but token in the detail is null. The system prop did not match a known System slug in Conflux. Only a matching system triggers the Active connection and access token path. For the Rapidmail use case, confirm the SystemSeeder has been run and that system="rapidmail" is spelled correctly.

conflux-registered never fires. The plugin has not called back yet. The widget polls GET /api/widget/connections/{id}/status every 3 seconds. If the plugin's token has been pasted correctly, the event fires as soon as Conflux sees the status change to active.

See also