How it works
Mobile integration follows a two-part architecture:
Your API key never leaves your server. The mobile app only ever sees a short-lived embed token.
You do not register an origin for a native app. The Allowed Embed Origins
list exists to constrain browsers, and a WebView loading an inline HTML string
has no origin to send. Requests that arrive without an
Origin header are
accepted on that basis, and the embed token — signed, scoped to one
organization, assessment and learner, and valid for 2 hours — is what
authorizes them.Register origins only for the web player, where a real browser origin exists.
Ionic and Capacitor are the exception: they serve your app from a real origin
(capacitor://localhost, ionic://localhost or an https:// host), so that
origin does need to be registered.The WebView HTML template
This is the universal mobile player. Load it in any WebView with the embed token injected:{{EMBED_TOKEN}} replaced server-side.
Never embed your API key in the WebView HTML. The embed token is short-lived (2 hours), consumed on submit, and scoped to a single learner and assessment — it is safe to put in client code.
Drag-and-drop needs a short press-and-hold
On a touch screen, drag-and-drop questions start after the learner holds the item still for about 120 ms. A tap-and-flick does not pick it up. This is deliberate. A finger landing on a draggable word is ambiguous: it could be the start of a drag, or the start of a scroll. Without the hold, every attempt to scroll the page that happened to begin on a word would drag the word instead, and a long assessment would be close to unscrollable. Holding still resolves the ambiguity. For comparison, dnd-kit defaults to 250 ms, and both Android and iOS use roughly 500 ms for their own system drag gestures, so Edpire is on the fast end. With a mouse there is no delay at all, just an 8 px movement threshold, because a mouse has no scrolling ambiguity to resolve.React Native
React Native apps can useEdpireClient directly for server-side operations — it uses fetch, which is available natively in React Native. For the player, open a WebView with the HTML template.
Server-side (your Node.js backend):
Flutter
Flutter apps call your backend viahttp or dio to fetch the embed token, then load the player HTML in a WebView.
Mint the token from your backend (Dart HTTP call):
flutter_inappwebview):
Native iOS / Android
The same HTML template works in any native WebView:- iOS:
WKWebView— useloadHTMLString(_:baseURL:)and receive messages viaWKScriptMessageHandler - Android:
WebView— useloadDataWithBaseURL()and receive messages viaaddJavascriptInterface