Skip to Content
SDK v3newInstallation

Installation

SDK 3.0 ships as an npm package and renders without an iframe in a Shadow DOM. For web you can also load it via ESM CDN (esm.sh/unpkg/jsDelivr); for Chrome extensions the only option is the bundled npm package (CWS review forbids remote code).

Website / SPA

pnpm add @monetize.software/sdk # or: npm i @monetize.software/sdk / yarn add @monetize.software/sdk
import { PaywallUI } from '@monetize.software/sdk/ui'; const paywall = new PaywallUI({ paywallId: '3', apiOrigin: 'https://YOUR_DOMAIN' }); paywall.open(); // native Shadow DOM, no iframe

Chrome Extension (MV3)

For extensions there’s a dedicated package @monetize.software/sdk-extension. It wraps SDK 3.0 in an offscreen document so a single state (auth session, bootstrap cache, trial counter, analytics) is shared across the popup, content scripts in every tab, and the service worker.

Working reference extension: github.com/monetize-software/sdk-examples/tree/main/browser-extension  — full MV3 setup: SW + offscreen + popup + content-script, floating Shadow-DOM widget, ApiGatewayClient with quota-driven auto-open, and a two-config vite build (ESM for SW/offscreen/popup, IIFE for content). Clone, set two env vars, npm install && npm run build, load dist/ in chrome://extensions.

pnpm add @monetize.software/sdk-extension preact

When to use @monetize.software/sdk-extension vs plain @monetize.software/sdk:

ScenarioPackage
Extension with popup + content scripts across tabs — sign-in in the popup should reflect on every tab instantly@monetize.software/sdk-extension
Popup only, no content scripts; or only one extension page (options)@monetize.software/sdk — sufficient

Minimal manifest.json

{ "manifest_version": 3, "name": "My Extension", "version": "1.0.0", "permissions": ["offscreen", "storage"], "host_permissions": ["https://YOUR_DOMAIN/*"], "background": { "service_worker": "sw.js", "type": "module" } }

Optional permissions:

  • "content_scripts" — if you want to render the paywall on third-party pages (not just the popup).

OAuth (Google / Apple / etc) does not require the "identity" permission — the SDK opens a popup window against your apiOrigin instead of using chrome.identity.

host_permissions — what to pick

host_permissions control two things: where the extension can fetch (from offscreen / SW / content-script) and which origins the content-script can inject into (together with content_scripts.matches).

This is the primary signal for Chrome Web Store review and AV vendors (Avast/Kaspersky/Norton). The narrower host_permissions, the less suspicion.

Extension host scenarioRecommendation
Extension already needs <all_urls> (recorder, all-site assistant, tool like Grammarly)Keep <all_urls>. SDK works as-is. Note: CWS review with <all_urls> goes through a manual audit and takes longer; AV vendors are more likely to flag such extensions as PUA. That’s the cost of broad injection, not an SDK risk.
Extension only talks to your backend and paywalls its own features (popup tool, side-panel app)Do NOT request <all_urls>. Your apiOrigin is enough: ["https://api.your-domain.com/*"]. No content-script injection on every site needed.
Hybrid — popup tool plus content script on a narrow list of domainsConstrain host_permissions + content_scripts.matches to those domains: ["https://*.your-target.com/*", "https://api.your-domain.com/*"].

Keep <all_urls> only when it’s genuinely needed for UX, and be ready to justify it in the CWS “Permission justification” field. “So the paywall works” is a bad justification; the SDK itself doesn’t require <all_urls>.

Initializing the three contexts

// service-worker.ts import { installRouter } from '@monetize.software/sdk-extension/sw'; installRouter({ offscreenUrl: chrome.runtime.getURL('offscreen.html') });
// offscreen.ts (loaded from offscreen.html) import { startOffscreenServer } from '@monetize.software/sdk-extension/offscreen'; startOffscreenServer({ paywallId: '3', apiOrigin: 'https://YOUR_DOMAIN', auth: true });
// content-script.ts (or popup.ts / options.ts) import { PaywallUI } from '@monetize.software/sdk-extension'; const paywall = new PaywallUI({ paywallId: '3', apiOrigin: 'https://YOUR_DOMAIN', auth: true }); paywall.open(); // same API as plain @monetize.software/sdk

Under the hood, content-script PaywallUI is a proxy via a chrome port into the offscreen document. All network traffic, auth refresh, and storage happen in offscreen; content only paints UI.

Telegram Mini App

Use the same @monetize.software/sdk you’d use on the web — a Telegram WebView is a regular browser context. Bundle size matters (Mini App start is blocked by load), so import narrowly:

import { PaywallUI } from '@monetize.software/sdk/ui'; // not from the full root

OAuth inside Telegram has its own quirks — see Authentication → OAuth.