Skip to main content
Elapse does not put React in your frontend. Your app can be Vue, Svelte, Rails, Django or plain HTML. The subscriber signs with their passkey in a window Elapse opens, and one script draws the meter afterwards — that script is the only thing Elapse adds to your page.
Already using React? Install @elapse/react and compose <Authorize> and <Meter> yourself, so your app ships one copy of React instead of two.

Your server does not change

Everything before the page is the same for every language. Follow the Quickstart — it has a cURL tab beside every call, so creating the Product, creating the Checkout session and handling subscription.canceled work in Python, Go, Ruby, PHP or anything that speaks HTTP. Your secret key stays there, where it belongs. Only the Quickstart’s last step — rendering the meter — is written in React. This page is that step in your stack instead.

Your page

The cs_… session id is created per subscriber by your server, so the page asks for one when the subscriber starts:
That is the whole frontend. mount renders the authorisation step, opens the signing window, and replaces itself with the live meter when the subscriber accepts. The build carries its own React, react-dom and motion (~65 KB gzipped), so you install nothing and your framework never sees them.

Options

A second mount on the same element replaces the first rather than stacking.

Which of the two fires

onAuthorised and onStarted are alternatives, not a sequence. Exactly one of them fires when the subscriber signs, and which one is decided by the Product’s start_mode: Merchant mode exists for a resource that has to be ready first — a container to boot, a runner to warm, a stream to open. You do that work, then call subscriptions.start from your server, and the meter begins. Until you do, the subscriber is charged nothing; a session you never start is cancelled and refunded in full after fifteen minutes. So a checkout-mode integration listens for onStarted, and a merchant-mode one listens for onAuthorised and starts the meter itself. Passing both, as above, is the safe default while you are deciding.

Where access is really decided

onStarted and onStopped are for your interface — reveal the product, hide it again. They are browser callbacks, so they are not proof of anything: a closed laptop fires no callback, and neither does a tab that crashed. Entitlement belongs on your webhook endpoint, where subscription.created and subscription.canceled arrive signed from Elapse. Grant on one, revoke on the other, and verify the signature before you parse the body. Signatures has the scheme and a test vector; the events catalogue has every payload you can receive. While you are building, elapse listen --forward localhost:3000/webhooks delivers them to your laptop with no tunnel.

Pause and Resume

Leave onPauseRequest and onResumeRequest out and the meter shows no such buttons. Pass them and it shows both — as requests to you. Nothing is signed in the browser and nothing reaches Elapse from it. Your server answers by calling subscriptions.pause and subscriptions.resume, and the meter follows once the change confirms. Paused seconds are never billed. The subscriber never gets a Stop button for a meter you started; stopping it stays yours, through whatever control your own page offers. Subscriptions has the rule.