> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ripio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Session lifecycle

> How long a widget session lasts, the events the widget emits, and how to renew a session without reloading your page.

### How long a session lasts

| Stage                                                                                    | Lifetime                           |
| ---------------------------------------------------------------------------------------- | ---------------------------------- |
| Session code from [`POST /auth`](/crypto-as-a-service/widget/get-started/authentication) | 2 minutes, **one use**             |
| Session, once the widget redeems the code                                                | 1 hour from your `POST /auth` call |

The session doesn't extend with activity. When it ends, the widget stops operating and asks you for a new code.

### Events

The widget emits DOM events on the `<ripio-crypto-widget>` element. They bubble and cross the Shadow DOM boundary, so you can listen on the element itself or on any ancestor.

| Event                   | `detail`                     | When                                                                                                                                                      |
| ----------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ripio-session-expired` | `{ reason: "session_lost" }` | The session ended: the code was invalid, expired or already used, the hour ran out, or Ripio revoked it. Fired as soon as it happens.                     |
| `ripio-session-expired` | `{ reason: "user_retry" }`   | The user pressed the button on the "session ended" screen.                                                                                                |
| `ripio-handoff`         | `{ reason: "not_operable" }` | The session is valid, but the user can't operate yet — for example, their identity verification isn't complete. Send them to the right place in your app. |

In a WebView there is no page of yours to listen on, so the widget also posts `{"type": "ripio-session-expired"}` to your app's native bridge — see [Mobile / WebView integration](/crypto-as-a-service/widget/get-started/webview#native-android-and-ios).

### Renewing a session

Request a new code from your server and pass it to the widget. It starts the new session and returns the user to the home screen, **without reloading your page**:

```javascript theme={null}
const widget = document.querySelector("ripio-crypto-widget");

widget.addEventListener("ripio-session-expired", async () => {
  const { session_code } = await fetch("/your-backend/ripio-session").then((r) => r.json());
  widget.renew(session_code);
});
```

Setting the `code` property again has the same effect as calling `renew`. In a WebView, you can also load the same page with a new `#_co=` fragment.

<Warning>
  Reloading the page doesn't renew anything. The code in the URL was already used, so a reload lands on the same "session ended" screen. The widget doesn't reload your page on its own either.
</Warning>

<Note>
  A new code can belong to a different `external_ref` — for example, if a different user logs into your app on the same device. The widget starts from a clean state for every renewal.
</Note>
