> ## 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.

# Embedding the widget

> The script tag and the web component's attributes.

The widget is a native [web component](https://developer.mozilla.org/en-US/docs/Web/Web_Components). To use it, import the script, mount the element in your page, and hand it the [session code](/crypto-as-a-service/widget/get-started/authentication) your server just requested:

```html theme={null}
<script
  type="module"
  src="https://b2b-crypto-widget-front.sandbox.ripio.com/bundle.v<version>.<hash>.js"
  integrity="sha384-<hash>"
  crossorigin="anonymous"
></script>

<ripio-crypto-widget currency="ARS" lang="es"></ripio-crypto-widget>

<script>
  // Set as a property, not an attribute, so the code never sits in your page's markup.
  document.querySelector("ripio-crypto-widget").code = "<session_code>";
</script>
```

`<ripio-crypto-widget>` is the **only** public element. It works in any framework that supports native web components — React, Next.js, Vue, Angular — or standalone HTML.

### Versions and integrity

There's no fixed `bundle.js`. Each release publishes a versioned file, `bundle.v<version>.<hash>.js`, and its [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) hash. Your Ripio contact sends you both with each release. Pin them in your snippet and update them when you adopt a new release:

* With `integrity`, the browser refuses to run the file if a single byte differs from the release you pinned, so a tampered CDN can't run code inside your page.
* `crossorigin="anonymous"` is required alongside `integrity`.
* The script tag is the only file you reference. The design tokens and translations ship inside the bundle. The widget loads its [fonts](/crypto-as-a-service/widget/configuration/theming#fonts) by itself, from the same host.

### Content Security Policy

When the widget is embedded in your page, your page's CSP applies to it. It needs to allow:

| Directive | Value | Why |
| - | - | - |
| `script-src` | The widget's host | The bundle |
| `connect-src` | The widget API's host | The widget's only backend |
| `font-src` | The widget's host | The fonts the widget serves |
| `style-src` | `'unsafe-inline'` | The widget injects its design tokens and your account theme as `<style>` elements |

If your policy has a restrictive `default-src`, also allow `img-src data: blob:`, which the widget uses for QR codes and icons.

### Attributes

| Attribute / property | URL parameter | Default | Description |
| - | - | - | - |
| `code` | `_co` | `""` | The one-time session code from [`POST /auth`](/crypto-as-a-service/widget/get-started/authentication). Prefer setting it as a property. |
| `lang` | `_la` | `es` | UI language: `es`, `pt` or `en`. |
| `currency` | `_cu` | `""` | Base fiat currency. |

The widget reads the session code once, redeems it, and then removes it: the `code` attribute is dropped from the element and the property is cleared. The code works only once, so reading it back afterwards gives you nothing to reuse — mint a new one each time you open the widget.

<Note>
  **URL parameters win over attributes.** This matters for WebView integrations: the app points the WebView at `index.html#_co=…&_cu=…&_la=…` and can't set element attributes directly.
</Note>

Language precedence: an explicit `lang` attribute or `_la` query param wins; otherwise the widget uses the language configured for your account; otherwise it falls back to `es`.

### Passing parameters in the URL

For a WebView or an `<iframe>` pointed at the widget's own page, pass the parameters in the URL **fragment** (after `#`), not the query string:

```
https://b2b-crypto-widget-front.sandbox.ripio.com/index.html#_co=<session_code>&_cu=ARS&_la=es
```

Browsers never send the fragment to a server, so the session code stays out of CDN access logs and out of every `Referer` header. The query string (`?_co=…`) is still accepted, but prefer the fragment. Either way, the widget removes `_co` from the address bar and the browser history as soon as it reads it; `_cu` and `_la` stay.

See [Mobile / WebView integration](/crypto-as-a-service/widget/get-started/webview) for a full example.

### Language

The `lang` attribute (or `_la` query param) accepts:

| Value | Language |
| - | - |
| `es` | Spanish |
| `pt` | Portuguese |
| `en` | English |

### Theming

The widget's appearance follows your brand automatically once it's configured on your account — see [Theming](/crypto-as-a-service/widget/configuration/theming). You can also override it yourself with CSS custom properties on your page:

```css theme={null}
:root {
  --ripio-color-primary: #0064c8;
  --ripio-btn-border-radius: 8px;
  --ripio-font-family: "Nunito Sans";
}
```

These custom properties inherit into the widget's Shadow DOM, so the widget repaints itself with no further wiring on your side. Your account theme, when there is one, takes precedence over your page's values. `--ripio-font-family` only renders one of the [fonts the widget ships](/crypto-as-a-service/widget/configuration/theming#fonts).

### Session expiry

When the session ends — it lasts one hour — or the code didn't work, the widget shows a "session ended" screen and fires a `ripio-session-expired` event on the element. Listen for it, request a new code from your server, and call `renew`:

```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);
});
```

See [Session lifecycle](/crypto-as-a-service/widget/get-started/session-lifecycle) for every event the widget emits.

### Behavior inside your page

* The widget never navigates or routes through your page's URL — no deep links, no hash routing. The one change it makes is removing `_co` from the URL once, at startup, if you passed the session code there.
* Nothing inside it uses `position: fixed`; overlays and modals stay anchored to the widget's own container, never the page viewport.
* The widget doesn't load any third-party analytics or session-replay script.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.