Skip to main content
The @utilsio/react package provides a UtilsioProvider component and useUtilsio hook to integrate utilsio into your React application. This is the main interface for building subscription experiences.

UtilsioProvider

The UtilsioProvider is the root component that manages the SDK state and provides context to your application. It should wrap your app’s root or the entire section that needs access to utilsio.
Always place UtilsioProvider as high in your component tree as possible. If you only wrap a part of your app, only the wrapped components will have access to useUtilsio().

Props

appId
string
required
Your unique utilsio Application ID. This identifies your app to utilsio’s servers. You can find this in your utilsio dashboard.Example: "550e8400-e29b-41d4-a716-446655440000"
getAuthHeadersAction
function
required
An async function that returns authentication headers for signed requests. This function is called automatically whenever the SDK needs to make a request to utilsio (fetching subscriptions, canceling, creating new ones).
deviceId
string
required
The unique device identifier from the SDK
additionalData
string
Optional additional data to include in the signature (used for subscription operations)
signature
object
The returned signature for the data
timestamp
object
System timestamp to prevent replay attack and tampering
Why it’s important: This ensures your UTILSIO_APP_SECRET never leaves your server. The backend computes HMAC signatures using the secret, which prevents tampering with requests.
See Server SDK Reference for implementation details of the signing endpoint.
children
ReactNode
required
Your application components. Everything wrapped by the provider can access useUtilsio().
utilsioBaseUrl
string
default:"https://utilsio.dev"
The base URL for the utilsio API and embed page. This will be useful later as utilsio rollout sandbox environment.
For now, keep the default value for this prop
Example: "https://utilsio.dev"
parentOrigin
string
default:"window.location.origin"
Your app URL. This is used to establish secure connection with utilsio.Example: "https://myapp.com"

Complete Usage Example (Next.js 16 - App Router)

src/app/layout.tsx
import { UtilsioProvider } from "@utilsio/react/client";

async function getAuthHeaders({
  deviceId,
  additionalData,
}: {
  deviceId: string;
  additionalData?: string;
}) {
  const response = await fetch("/api/sign", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ deviceId, additionalData }),
  });

  if (!response.ok) throw new Error("Auth failed");
  return response.json();
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <UtilsioProvider
          appId={process.env.NEXT_PUBLIC_UTILSIO_APP_ID!}
          utilsioBaseUrl={process.env.NEXT_PUBLIC_UTILSIO_APP_URL!}
          getAuthHeadersAction={getAuthHeaders}
        >
          {children}
        </UtilsioProvider>
      </body>
    </html>
  );
}

useUtilsio Hook

The useUtilsio hook provides access to the current state and actions of the SDK. This is how you interact with utilsio from your components.
This hook can only be used in client components (marked with "use client"). If you need to use it in a Server Component, create a separate client component and pass data through props.

Basic Usage

"use client";

import { useUtilsio } from "@utilsio/react/client";

export function MyComponent() {
  const {
    user,
    deviceId,
    currentSubscription,
    loading,
    error,
    refresh,
    cancelSubscription,
    redirectToConfirm,
  } = useUtilsio();

  // Use these values in your component
}

State Props

user
UtilsioUser | null
The currently authenticated user (happy path), or null if not logged in to utilsio.dev yet (normal path).
deviceId
string | null
A unique identifier for the current device/browser. This is generated automatically by the SDK and persisted in a cookie on the utilsio origin.
This ID is just for reference, DO NOT rely on this for critical authentication flows as it might change across browser sessions and data clearance.
currentSubscription
UtilsioSubscription | null
The active subscription for the current user/device combination. Returns null if there’s no active subscription.
loading
boolean | null
Whether the SDK is currently fetching initial state from the server. This is true while the SDK initializes and false once it’s ready.
It is advised to wait for loading to be true before rendering your page / component, although it is ultimately up to you.
error
string | null
An error message if something went wrong during initialization or while performing actions.Common errors:
  • "Failed to authenticate" - Signing endpoint is down or unreachable
  • "Network error" - Connection issues with utilsio servers
  • "Invalid credentials" - App ID or signing is incorrect
  • "User must be authenticated to cancel subscription" - User or deviceId is null
  • "User must be authenticated to subscribe" - User or deviceId is null

Actions

refresh
function
Manually refresh the user state and subscription info from the server. Useful after making changes or periodically polling for updates.
This function does not accept any parameters
This function does not return any values
When to use:
  • After subscribing to / cancelling a subscription
  • Periodically in long-running apps
  • When returning from external authentication flows
  • When you suspect subscription state is stale
  • Or just simply every time page reload - it’s a simple function
This function:
  • Sets loading to true while operating
  • Returns early if deviceId is null (no user authenticated)
  • Updates currentSubscription with the response
cancelSubscription
function
Cancel one or more subscriptions.
subscriptionsId
string[]
required
Array of subscription IDs to cancel (typically just one)
This function does not return any values
When to use:
  • After subscribing to / cancelling a subscription
  • Periodically in long-running apps
  • When returning from external authentication flows
  • When you suspect subscription state is stale
  • Or just simply every time page reload - it’s a simple function
After cancellation completes, currentSubscription becomes null.
redirectToConfirm
function
Cancel one or more subscriptions.
appId
string
required
Your utilsio app ID (same as in UtilsioProvider).
appName
string
required
Display name of your app shown during the subscription flow.Example: "My Premium App"
amountPerDay
string
required
The daily subscription amount as a string. This is the billing amount per day that will be charged to the user.
The amount is in POL / day unit, so passing 1 would mean that the user will be charged 1 POL / day or 30 POL / month
URL to your app’s logo. Displayed during the subscription flow.
appUrl
string
Your app’s URL. Used for redirects and context.
nextSuccess
string
required
URL to redirect the user to after successful subscription. Typically your success page or home page.Example: "https://myapp.com/success"
nextCancelled
string
required
URL to redirect the user to if they cancel the subscription flow. Typically back to your home page.Example: "https://myapp.com/cancelled"
This function does not return any values

Complete Usage Example (Next.js 16 - App Router)

Here’s a fully functional subscription component using all the pieces:
src/components/SubscriptionWidget.tsx
"use client";

import { useUtilsio } from "@utilsio/react/client";
import { useCallback, useState } from "react";

export function SubscriptionWidget() {
  const {
    user,
    currentSubscription,
    loading,
    error,
    redirectToConfirm,
    cancelSubscription,
  } = useUtilsio();

  const [isCancelling, setIsCancelling] = useState(false);
  const [cancelError, setCancelError] = useState<string | null>(null);

  const handleSubscribe = useCallback(() => {
    const appUrl = process.env.NEXT_PUBLIC_APP_URL!;

    redirectToConfirm({
      appId: process.env.NEXT_PUBLIC_UTILSIO_APP_ID!,
      appName: "Premium App",
      amountPerDay: (10 / 30).toFixed(6), // $10/month
      appUrl,
      nextSuccess: `${appUrl}/success`,
      nextCancelled: `${appUrl}/`,
    });
  }, [redirectToConfirm]);

  const handleCancel = useCallback(async () => {
    if (!currentSubscription) return;
    if (!confirm("Cancel your subscription?")) return;

    setIsCancelling(true);
    setCancelError(null);

    try {
      await cancelSubscription([currentSubscription.id]);
    } catch (err) {
      setCancelError(err instanceof Error ? err.message : "Unknown error");
    } finally {
      setIsCancelling(false);
    }
  }, [currentSubscription, cancelSubscription]);

  // Loading state
  if (loading) {
    return <div className="p-4">Loading...</div>;
  }

  // Error state
  if (error) {
    return <div className="p-4 text-red-600">Error: {error}</div>;
  }

  // Not logged in
  if (!user) {
    return (
      <div className="p-4">
        <p>Please log in to subscribe</p>
      </div>
    );
  }

  // Has active subscription
  if (currentSubscription) {
    const dailyAmount = parseFloat(currentSubscription.amountPerDay);
    // Using 30-day month approximation for display
    const monthlyAmount = (dailyAmount * 30).toFixed(2);

    return (
      <div className="p-4 border rounded">
        <h2>Your Subscription</h2>
        <p>Email: {user.email}</p>
        <p>Amount: ~${monthlyAmount}/month</p>
        <p>Started: {new Date(currentSubscription.createdAt).toLocaleDateString()}</p>

        <button
          onClick={handleCancel}
          disabled={isCancelling}
          className="mt-4 px-4 py-2 bg-red-500 text-white rounded"
        >
          {isCancelling ? "Cancelling..." : "Cancel Subscription"}
        </button>

        {cancelError && <p className="text-red-600 mt-2">{cancelError}</p>}
      </div>
    );
  }

  // No subscription - show subscribe button
  return (
    <div className="p-4 border rounded">
      <h2>Subscribe</h2>
      <p>Email: {user.email}</p>
      <p>~$10/month for premium features</p>

      <button
        onClick={handleSubscribe}
        className="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
      >
        Subscribe Now
      </button>
    </div>
  );
}

Environment Variables

When setting up UtilsioProvider, you’ll typically use these environment variables:
NEXT_PUBLIC_UTILSIO_APP_ID=your-app-id

NEXT_PUBLIC_APP_URL=https://yourapp.com
NEXT_PUBLIC_UTILSIO_APP_URL=https://utilsio.dev
The NEXT_PUBLIC_* prefix means these are safe to expose in the browser. Your UTILSIO_APP_SECRET should NOT be exposed and should only be used on the backend in your signing endpoint.
Last modified on January 15, 2026