Session Handling
Session handling is the most important part of a Fluid integration and the most common source of first integration problems.
What a session is
Section titled “What a session is”Fluid doesn’t run its own login. It trusts your site to authenticate the user, then identifies that user through the operator-id, user-id, session-id, locale, country and currency attributes for the length of their session.
Fluid doesn’t own or interpret session-id: it’s your platform’s session ID, passed through as is. It travels with the user’s transactions and can come back to your platform later in the payment lifecycle, for example when a payment provider presents it to attribute or verify activity. So it must be the real, current session ID of the authenticated user — not a placeholder, not a stale value, and nothing your platform wouldn’t recognise when it comes back.
The golden rules
Section titled “The golden rules”- Initialise once after authentication — not on page load before login or on every render
- Keep
session-idstable — must reflect the current session, not change on every render. An empty, placeholder, stale or constantly changingsession-idis the number one cause of failed integrations - Rotate sessions by updating the attribute — push the new value to
session-idrather than removing the widget - Never change identity attributes on mounted elements —
operator-id,user-id,locale,country, andcurrencyare read once at mount; setting a new value on a live element does nothing, and the widget silently keeps the identity it started with - Wait for
initialisedbefore opening — never setopen="true"before this event fires; opening earlier shows an empty or broken wallet - Remove the widget on logout — take it from the DOM when the session ends
- Keep exactly one widget in the DOM — multiple widgets cause unpredictable behaviour
Session lifecycle
Section titled “Session lifecycle”- User authenticates on your site
- Load Fluid script and initialise widget with identity attributes
- Widget remains mounted throughout the session; update reactive attributes as needed
- On logout, remove widget from the DOM
Attribute management
Section titled “Attribute management”| Action | Method | Reason |
|---|---|---|
| Rotate session ID | Update session-id attribute |
Observed live, even during open transactions |
| Change user/operator/locale/country/currency | Remove element, mount new one | These are read once at mount; changing them on a live element does nothing |
| Open wallet | Set open="true" after initialised |
Wallet only ready after initialisation |
| End session | Remove from DOM | Clean shutdown, emits destroyed |
fluid.init() notes
Section titled “fluid.init() notes”This method pre-warms the widget for faster opening but does not open the wallet.
- Call it once per session, right after loading the script
- 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 can’t guarantee the spacing - Uses
countryCodeandcurrencyCodeparameters (notcountryandcurrencylike HTML attributes)
Fluid’s internal authentication
Section titled “Fluid’s internal authentication”- Per browser tab — each tab starts fresh
- Refreshes automatically when credentials expire
- No “session expired” event is emitted
- Separate from your
session-id— you must keepsession-idcurrent
A refused session
Section titled “A refused session”Before the widget initialises, Fluid checks the attributes it was given, and checks the player’s session with your platform or payment provider. If they aren’t accepted, the widget doesn’t open and emits fluid-error with initialisation-failure, code: 'SESSION_REJECTED' and a reason. Check that:
operator-idis the one Fluid Payments gave you for this environment;user-idandsession-idare the player’s own and current, not an expired or placeholder session;countryandcurrencyare the player’s own, as your platform holds them.
If Fluid couldn’t reach your platform or payment provider to check the session, the widget tries once more after a short wait. If that fails too, it emits initialisation-failure with code: 'SESSION_CHECK_UNAVAILABLE' instead. Nothing is wrong with your attributes, and the player can try again shortly.
With programmatic initialisation, the refusal happens before any element exists, so there is no event yet: the promise returned by fluid.init(...) rejects, and its error carries the same reason as its message. Catch that rejection and treat it as the refusal: an element mounted afterwards doesn’t open either, and with only the attributes programmatic initialisation asks for, it reports missing attributes rather than SESSION_REJECTED.
The session can also be refused later: while the cashier is open, or when a page reload restores the widget from the browser instead of initialising it again. There is no initialisation-failure then. The next deposit or withdrawal fails instead, and its deposit-failure or withdrawal-failure event carries errorCode: 'SESSION_REJECTED'. If Fluid couldn’t reach your platform or payment provider to check the session, the code is SESSION_CHECK_UNAVAILABLE instead, and the player can try again shortly.
For security, neither the event nor the rejection says which of these failed. If you can’t find the cause, contact Fluid Payments with the time of the failure and the player’s user-id.
Events to monitor
Section titled “Events to monitor”| Event | Message | Meaning |
|---|---|---|
fluid-info |
initialised |
Widget is ready to open |
fluid-info |
destroyed |
Widget has shut down |
fluid-error |
initialisation-failure |
Configuration failed, for example because of a bad session-id or a network or backend problem. With code: 'SESSION_REJECTED', the player’s session was refused; with code: 'SESSION_CHECK_UNAVAILABLE', it couldn’t be checked for now. See A refused session |
fluid-error |
invalid-init-attributes |
An init attribute failed validation |
fluid-error |
invalid-user-data |
User data format incorrect |
Common mistakes
Section titled “Common mistakes”Rotating session IDs on every render
Section titled “Rotating session IDs on every render”// Bad: changes on every renderwidget.setAttribute('session-id', getLatestCsrfToken());
// Good: stable session identifierwidget.setAttribute('session-id', getStableSessionId());Mounting before authentication
Section titled “Mounting before authentication”<!-- Bad: widget exists before login --><fluid-widget session-id="" ...></fluid-widget>// Good: create widget only after loginonLoginSuccess((session) => { const widget = document.createElement('fluid-widget'); widget.setAttribute('session-id', session.id); document.body.appendChild(widget);});Not removing the widget on logout
Section titled “Not removing the widget on logout”function onLogout() { document.querySelector('fluid-widget')?.remove();}Cross-tab inconsistencies
Section titled “Cross-tab inconsistencies”Sessions are per-tab. Ensure initialisation runs in every browser tab — sessions don’t share across tabs.