Session handling
Getting session handling right is the single most important part of a Fluid integration, and it is the most common source of first integration problems. This page explains what a session means to Fluid, the rules you must follow, and the mistakes that cause the support requests we see most often.
If you read only one thing: pass the real, current session ID of your authenticated user in session-id, initialise the widget once right after the user logs in, and keep that value stable for the life of the session. And if your platform refreshes or rotates the session ID at any point, update the session-id attribute with the new value: the attribute is observed even while the cashier is open, so the widget picks it up live.
What a session is
Fluid does not run its own login. It trusts the host site to authenticate the user, then represents that authenticated user through a small set of attributes on the widget element:
operator-idis your operator identifier, provided by Fluid Payments.user-idis the identifier of the authenticated user.session-idis the current session ID of the authenticated user.locale,countryandcurrencydescribe the user's locale (IETF BCP 47), country (ISO 3166-1 alpha-3) and currency (ISO 4217).
Together these identify the user to Fluid for the duration of their session.
Fluid does not own or interpret the session-id. It is your platform's session ID, passed through Fluid as is. It travels with the user's transactions and can reach back to your platform later in the payment lifecycle, for example when a payment provider presents it to you to attribute or verify the activity. Because it round trips through that lifecycle, keep it hygienic: pass the real, current session ID of the authenticated user, not a placeholder, not a stale value, and nothing your platform would fail to recognise when it comes back.
The session lifecycle
- The user authenticates on your site.
- You load the Fluid script and initialise the widget once, passing the identity attributes above.
- The widget stays mounted for the whole session. You update reactive attributes (such as
balanceoropen) as needed, but you do not re-initialise. - On logout or session end, you remove the widget from the DOM.
Golden rules
Initialise once, right after authentication. Initialise when the user logs in, not on page load before login, and not on every render. See Automatic Init and Programmatic Init.
Keep session-id stable. It must be the current session ID of the authenticated user, and it must not change on every render or route change. An empty, placeholder, stale, or constantly changing session-id is the number one cause of failed integrations.
Rotate a session by updating the attribute, not by tearing down. If your platform issues a new session ID for the same authenticated user, push the new value onto the session-id attribute.
session-id is one of the few attributes observed even while the widget is open. Whenever your platform refreshes or rotates the session ID, set the new value on the attribute immediately, mid transaction included. The widget adopts the new session live, without you removing and recreating the element. Forgetting this leaves the widget on a session your platform no longer recognises.
This applies to <fluid-widget> and <fluid-virtual>. The inline <fluid-quick-deposit> reads session-id once when mounted and does not adopt a rotated session; after a rotation, re-mount the Quick Deposit element with the new value.
Never change the other identity attributes on a mounted element. operator-id, user-id, locale, country and currency are read once when the element mounts and are not observed afterwards: setting a new value on a live element does nothing, and the widget silently keeps the identity it started with. For a genuine identity change (for example a real account switch), remove the element from the DOM and mount a fresh one with the new values.
Wait for initialised before opening. Never set open="true" before the widget emits the initialised event. Opening earlier shows an empty or broken wallet. See Events and errors.
Remove the widget on logout. Take <fluid-widget> out of the DOM when the session ends so it shuts down cleanly. You will see a destroyed event.
Keep exactly one widget in the DOM. More than one <fluid-widget> mounted at the same time causes unpredictable behaviour.
What to do when something changes
| You need to | Do this | Why |
|---|---|---|
| Rotate the session ID | Set the new value on the session-id attribute | Observed live, even while the cashier is open; the widget adopts the new session without teardown |
| Change user, operator, locale, country or currency | Remove the element and mount a fresh one with the new values | These attributes are read once at mount; changing them on a live element does nothing |
| Open the wallet | Set open="true" after the initialised event | The wallet is only ready to open once initialisation completes |
| End the session (logout) | Remove the element from the DOM | The widget shuts down cleanly and emits destroyed |
fluid.init() is a pre-warm, not a way to open the wallet
fluid.init() (Programmatic Init) prepares the widget ahead of time so it opens faster. It is an optimisation you call once per session, immediately after loading the script. It does not open the wallet, and it is throttled to roughly once every two seconds: a call made too soon after the previous one returns a promise that rejects with Error('Function call is throttled. Please wait.'), so handle the rejection if you cannot guarantee the spacing. The wallet is opened by the custom element through its open attribute, after initialised.
Watch the field names: fluid.init() takes countryCode and currencyCode, while the HTML attributes are country and currency. Mixing them up is a common slip.
Fluid handles its own authentication
After init, the widget authenticates to Fluid's services on its own, using an internal credential that is not a host concern. You never read, store, or refresh it. Three behaviours are worth designing around:
- It is per browser tab. A new tab starts a fresh instance, so the widget initialises again in each tab. Do not try to share this state across tabs yourself.
- It refreshes automatically. When the credential expires during a session, the widget renews it transparently. You do not need to do anything.
- There is no "session expired" event. Because refresh is automatic, the widget does not emit a client side expiry notification, so do not build logic that waits for one. If a genuine problem stops the widget configuring itself, you receive a
fluid-errorwithinitialisation-failureinstead.
This is separate from session-id, which is your platform's session ID: keeping that attribute current remains your responsibility, as described above.
Signals to handle
Subscribe to the widget's events and react to the session relevant ones. The full catalogue is on the Events and errors page. The ones that matter for session handling are:
fluid-infoinitialised: the widget is ready, and only now may you open it.fluid-infodestroyed: the widget has shut down.fluid-errorinitialisation-failure: the widget could not configure itself (for example a badsession-id, or a network or backend problem).fluid-errorinvalid-init-attributesorinvalid-user-data: an attribute you passed did not validate, for example an invalidlocale(the widget falls back toen) or malformed Sweepstakes data. The exact triggers are listed in Events and errors.
Common mistakes
The most frequent session mistakes, with their symptoms and fixes, are collected on the Common pitfalls page together with the other integration pitfalls.
Next steps
- Quick start: a minimal, correct integration from end to end.
- Common pitfalls: symptom to fix tables for the mistakes we see most.
- Fluid Widget: the widget integration guide.
- Framework integrations: session safe patterns for React, Angular, Vue and Svelte.