New: allowances counted across every runtime of a seat See what's new →
← Back to Blog

Getting Started with Monaiq in React

· Engineering · Curtis Watson · 7 min read

The Scenario

You've built a React app — maybe a dashboard, a design tool, or a productivity suite. It has a free tier with basic functionality and a Pro tier with premium features. The code works, users are signing up, and now you need to actually gate those Pro features based on who's paying.

In the .NET world, you have dependency injection and server-side checks. In React, you need something different: a context provider that makes licensing available everywhere in your component tree, and client-side assertion evaluation against a verified authorization, so a check doesn't mean a round trip.

That's exactly what Monaiq's React SDK provides. Let's set it up.

Install the SDK

The React SDK is published on npm as @sidub-inc/licensing-client. React is an optional peer dependency (16.8 or later), so the same package also runs in plain Node.

terminal
npm install @sidub-inc/licensing-client

That's it for dependencies. The SDK is TypeScript-first with full type definitions included — no separate @types package needed. If you're using JavaScript, the types are still there for editor IntelliSense.

Configure the Provider

Monaiq's React integration uses a context provider pattern — the same approach as React Router, Redux, or any other library that shares state across your component tree. Wrap your app (or the section that needs licensing) in a LicensingProvider:

App.tsx
import { LicensingProvider } from '@sidub-inc/licensing-client';

function App() {
  return (
    <LicensingProvider config={{
      licenseServiceUri: 'https://api.monaiq.com/licensing',
      encodedCredential: process.env.REACT_APP_LICENSE_CREDENTIAL
    }}>
      <YourApp />
    </LicensingProvider>
  );
}

The encodedCredential is a SIDUB_LIC_... license code, issued on a seat's page in the portal or returned by a completed purchase. It carries the seat id, a runtime token scoped to that one seat, and the public key used for signature validation — all in one string, and no account API key, so it is safe to ship.

The provider creates a LicensingClient instance and makes it available to every component below via React context. The client is memoized — it only recreates when your config actually changes.

Check Authorization

Now the useful part. In any component inside the provider, useLicensingContext hands you the shared client, and getAuthorization fetches the license authorization:

LicenseStatus.tsx
import { useEffect, useState } from 'react';
import { useLicensingContext, LicensingError } from '@sidub-inc/licensing-client';
import type { LicenseAuthorization } from '@sidub-inc/licensing-client';

function LicenseStatus() {
  const client = useLicensingContext();
  const [authorization, setAuthorization] = useState<LicenseAuthorization | null>(null);
  const [error, setError] = useState<LicensingError | null>(null);

  useEffect(() => {
    client.getAuthorization()
      .then(setAuthorization)
      .catch((err) => setError(err instanceof LicensingError ? err : new LicensingError(String(err))));
  }, [client]);

  if (error) return <div>License error: {error.code ?? error.message}</div>;
  if (!authorization) return <div>Checking license...</div>;

  return (
    <div>
      License active
      {authorization.signatureValidated && <span> ✓ Cryptographically verified</span>}
    </div>
  );
}

The authorization carries everything you need: the features it grants, when it expires, and whether the signature was cryptographically validated. A failure is a LicensingError with the server's machine-readable code and a correlation id to quote to support. That last part matters — it means the authorization hasn't been tampered with since the server issued it. The validation happens in the browser using the Web Crypto API, matching the same security model as the .NET SDK.

Gate Features

Checking authorization is useful, but the real power is gating features. The client's assertLicense evaluates a license assertion against an authorization and returns a simple boolean.

PremiumDashboard.tsx
import { useEffect, useState } from 'react';
import {
  useLicensingContext,
  ServiceAccessAssertion,
  ServiceAccessLevel
} from '@sidub-inc/licensing-client';
import type { LicenseAuthorization } from '@sidub-inc/licensing-client';

function PremiumDashboard() {
  const client = useLicensingContext();
  const [authorization, setAuthorization] = useState<LicenseAuthorization | null>(null);

  useEffect(() => {
    client.getAuthorization().then(setAuthorization).catch(() => setAuthorization(null));
  }, [client]);

  const allows = (featureKey: string) =>
    authorization !== null && client.assertLicense(
      ServiceAccessAssertion.create(featureKey, ServiceAccessLevel.Allowed),
      authorization
    );

  const hasAnalytics = allows('advanced-analytics');
  const hasPdfExport = allows('pdf-export');

  return (
    <div>
      {hasAnalytics ? <AnalyticsPanel /> : <UpgradeCard feature="Analytics" />}
      {hasPdfExport ? <ExportButton /> : <UpgradeCard feature="PDF Export" />}
    </div>
  );
}

ServiceAccessAssertion.create() creates a typed assertion object. assertLicense evaluates it against the authorization — entirely locally, with no network call. It returns true or false. Repeated getAuthorization calls are served from the client's cache, so gating per component is cheap.

This is the same assertion pattern used in the .NET SDK — ServiceAccessAssertion checks for boolean access, RateLimitAssertion handles rate-limited features, and QuotaAssertion handles allowances. Same concepts, TypeScript API.

Track Usage

If your product includes consumption-based features — API calls, file exports, AI generations — you need to report usage back to Monaiq. The client's performOperation method counts the use against the feature and, with consumptionServiceUri: 'https://api.monaiq.com/consumption' in the provider's config, reports it to Monaiq:

ExportButton.tsx
import { useLicensingContext } from '@sidub-inc/licensing-client';

function ExportButton() {
  const client = useLicensingContext();

  const handleExport = async () => {
    // Report the operation to Monaiq
    await client.performOperation({
      feature: { featureKey: 'pdf-export' },
      operationType: 'increment',
      quantity: 1,
      timestamp: new Date()
    });

    // Then perform the actual export
    await generatePdfExport();
  };

  return <button onClick={handleExport}>Export PDF</button>;
}

The useLicensingContext hook gives you direct access to the LicensingClient instance for imperative operations. Recorded usage appears in your analytics by feature, by customer and by offering, and is billed for the period it happened in.

Next Steps

That covers the essentials: install, configure, authorize, gate, and track. You've gone from a React app with no licensing to one that enforces entitlements and reports usage — with about 30 lines of code.

From here, you can explore:

  • Rate limiting — use RateLimitAssertion for time-windowed feature limits
  • Feature introspection — use FeatureExistsAssertion to check if a feature exists in the authorization
  • Standalone client — construct new LicensingClient(config) for non-React scenarios (e.g., utility scripts, Node.js backends)
  • In-app purchase — use PurchaseClient to sell your offerings from an Electron, desktop or mobile shell
  • Product setup — define your products, offerings, and features in the Monaiq dashboard or via the MCP server

The React SDK uses the same Monaiq backend as the .NET SDK. If you're already using Monaiq for a server-side application, your products, offerings, and licenses work with the React client out of the box — no reconfiguration.

Check out the React SDK landing page for a full feature overview, or dive into the documentation for the complete API reference.

Ready to license your React app?

Create your free account and start enforcing in minutes.

Ready to monetize your software?

Free while Monaiq is in preview. No credit card required.