Installation
How to install, initialize, and configure the Fruga Relay SDK for your platform. This reference covers the full installation steps via package managers, configuration options, and how to handle SDK lifecycle events.
1. Install the SDK
The Fruga SDK is published on the public npm registry — no registry configuration or authentication needed. Install @fruga/sdk using your preferred package manager.
pnpm unless your project strictly enforces another package manager.pnpm add @fruga/sdk
The SDK exposes two integration surfaces:
// React — component and hook
import { FrugaWidget, useFrugaWidget } from '@fruga/sdk/loader/react';
// Imperative API — any framework or vanilla JS
import { init, mount, unmount } from '@fruga/sdk/loader';
2. Adding the container (Optional)
The widget can render as a modal overlay or mount inline within a specific element. If you want it to render inline, add an empty container element to your page.
<div id="fruga-widget-root" style="width:100%; min-height:600px;"></div>
3. Initialising the widget
Call init() to boot up the widget. By default, the widget will mount immediately (autoMount: true).
partnerKey and the access token your own backend returns - your PARTNER_SECRET never leaves your server. See the Authentication guide.Every example below passes an onTokenRequired callback. This is how the widget authenticates: it calls your endpoint, which signs an assertion and exchanges it for a Fruga access token server-side, then returns that token. The callback is shared across all three integration styles:
const onTokenRequired = async () => {
const res = await fetch('/fruga/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userRef: currentUser.id }),
});
if (!res.ok) throw new Error('Failed to fetch Fruga token');
const { accessToken } = await res.json();
return accessToken;
};
See Getting Started for the backend endpoint this calls.
React component (recommended)
The <FrugaWidget /> component renders its own container and handles init, mount, and cleanup through the React lifecycle:
import { FrugaWidget } from '@fruga/sdk/loader/react';
export const OffersPage = ({ partnerKey }) => (
<div style={{ width: '100%', minHeight: '600px' }}>
<FrugaWidget partnerKey={partnerKey} onTokenRequired={onTokenRequired} />
</div>
);
React hook (manual control)
Use useFrugaWidget when you want to decide when the widget mounts — for example behind a button:
import { useFrugaWidget } from '@fruga/sdk/loader/react';
export const OffersPage = ({ partnerKey }) => {
const { mount, unmount } = useFrugaWidget({
partnerKey,
onTokenRequired,
autoMount: false, // You control the mount timeline
});
return (
<div className="flex flex-col gap-4">
<div id="fruga-widget-root"></div>
<button onClick={() => mount()}>View Offers</button>
</div>
);
};
Imperative API (vanilla JS / other frameworks)
Outside React, call init() directly:
import { init, unmount } from '@fruga/sdk/loader';
await init({
partnerKey: process.env.NEXT_PUBLIC_PARTNER_ID,
onTokenRequired,
});
// Later, when tearing the page down:
unmount();
Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
partnerKey | string | Yes | Your public key identifying your partner environment - the NEXT_PUBLIC_PARTNER_ID value Fruga issued you. Separate values for development and production. |
onTokenRequired | function | In practice, yes | Async callback returning a fresh Fruga access token - not an assertion. The widget calls it on first load and whenever the token needs refreshing. Without it the widget cannot authenticate a user. |
containerId | string | No | The ID of the DOM element where the widget should mount (defaults to fruga-widget-root). If provided, it renders inline. |
autoMount | boolean | No | Controls automatic DOM injection. Defaults to true. Set to false if you want to call mount() manually later. |
userId | string | No | Optional identity context. The authoritative user identity comes from the userRef claim in the assertion your backend signs, not from this option. |
theme | 'light' | 'dark' | No | The initial visual theme. |
primaryColor | string | No | Hex code for the primary brand colour. |
Architecture & styling
The SDK mounts an iframe shell to prevent your CSS from leaking into our widget and vice versa (Shadow DOM isolation).
init(). Colours, theme defaults, launcher copy, and related appearance are configured for your partner environment on Fruga’s side and applied when the widget loads. See Customising the Interface and Branding. Do not attempt CSS overrides on the internal iframe structure, as it will break isolation.Troubleshooting
- Widget fails to render: Verify your
partnerKeyis correct for the environment. Ensure yourmount()logic aligns with yourautoMountsetting. - Widget mounts but shows no user data:
onTokenRequiredreturned an empty string or an invalid token. Do not catch errors inside the callback and return''- let them throw, so the failure is visible instead of surfacing as an empty widget. Check your token endpoint’s response in the Network tab. - Multiple widgets rendering: If using React 18+ strict mode, ensure the component isn’t unmounting/remounting excessively without proper cleanup (
unmount()), or wrap the initialization carefully so it only executes once.