Skip to content
View despia-native's full-sized avatar

Highlights

  • Pro

Block or report despia-native

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
despia-native/README.md

Part of Despia Convert

This repository supports Despia Convert and Despia V4 WebView applications. Despia Convert is the fastest way to turn an existing web application into an iOS or Android app while keeping the existing web codebase.

This project is actively supported for Convert and WebView-based applications.

For projects that require fully native UI and native rendering, use DSX Native, Despia's native-first platform (SwiftUI on iOS, Jetpack Compose on Android). Convert applications can migrate to DSX Native later if deeper native UI or performance is required. Despia does not charge a migration fee.

Current documentation: docs.despia.com

Add 50+ native iOS and Android capabilities to any web app (React, Vue, Angular, Svelte, Next.js, vanilla JS) through a single despia() function. Plus native offline support, a local SQLite database, and an on-device streaming CDN, solving 15 years of hybrid-app problems with modern runtime architecture.

npm

Full documentation


Installation

npm install despia-native
# pnpm add despia-native
# yarn add despia-native
import despia from 'despia-native';

Or via CDN:

<!-- UMD -->
<script src="https://cdn.jsdelivr.net/npm/despia-native/index.min.js"></script>
<!-- ESM -->
<script type="module">
  import despia from 'https://cdn.jsdelivr.net/npm/despia-native/+esm';
</script>

Quick Start

import despia from 'despia-native';

// Launch a RevenueCat paywall
despia(`revenuecat://launchPaywall?external_id=${userId}&offering=default`);

// Link the device to your user for OneSignal push
despia(`setonesignalplayerid://?user_id=${userId}`);

// Store a session token behind Face ID / Touch ID (survives reinstall)
await despia('setvault://?key=sessionToken&value=abc123&locked=true');

// Read it back later (prompts biometric)
const { sessionToken } = await despia('readvault://?key=sessionToken', ['sessionToken']);

No initialization. Open your app in the Despia runtime and it works.


Why Despia

Despia is a hybrid app runtime built on the web platform. The web handles what it's good at (logic, UI, routing, state, storage); everything else (biometrics, push, in-app purchases, background GPS, system pickers) is handed to a native engine via a single despia() call.

Works with any web codebase. Bring an existing app or start fresh with any framework, any build tool, any host. No framework lock-in, no proprietary hosting, nothing to migrate.

Full native offline support. @despia/local serves your web build from http://localhost, and the Local CDN streams cached media from device storage. For on-device database options, see the current Despia documentation. File transfers stream between native storage and the web layer without loading into the JS heap.

Push, monetization, ads, and attribution are built in: OneSignal, RevenueCat, AdMob, AppsFlyer. Pre-wired into the runtime, configured from the Despia dashboard, called from web code. Builds, signing, and store submission run from the browser. No Xcode, no Android Studio.


Contents


Environment Detection

The SDK only activates inside the Despia runtime. Gate native calls:

const isDespia = navigator.userAgent.toLowerCase().includes('despia');

const isDespiaIOS = isDespia && (
  navigator.userAgent.toLowerCase().includes('iphone') ||
  navigator.userAgent.toLowerCase().includes('ipad')
);

const isDespiaAndroid = isDespia && navigator.userAgent.toLowerCase().includes('android');

if (isDespia) despia('lighthaptic://');

For AI Coding

Full API context: llms.txt.

  • Import as default: import despia from 'despia-native'
  • Never write window.despia directly; the SDK uses it internally
  • There is no .init(), .ready(), or .setup(); the SDK exports a single function with no initialization
  • Do not mock or reimplement the SDK; mock implementations will not trigger the native runtime on real devices
  • Gate native calls with the environment check above
  • For Local Server apps, install via a package manager so the SDK ships with the build
  • Do not await localcdn://write with a watch key; use window.contentServerChange
  • For the upload API, read window.location.host; don't hardcode ports

API Reference

despia(command, watch?)

Parameter Type Description
command string A Despia protocol URL, e.g. 'lighthaptic://'
watch string[] Variable names to wait for

Returns a Promise that resolves when all watched variables are set, with a 30-second timeout. Long-running work (downloads, purchases, biometric prompts) reports back via global callbacks like window.onRevenueCatPurchase or window.contentServerChange instead. despia.variableName is equivalent to window.variableName.

Protocol format: feature://action?param1=value1&param2=value2


Deployment Models

Remote hydration (default). Binary ships without web assets; Despia fetches the current build on launch. Web updates do not require store resubmission.

Local Server. Build is cached on-device and served from http://localhost. See Local Server.

Version gating. Use despia-version-guard to gate features by minimum runtime version:

import { VersionGuard } from 'despia-version-guard';

<VersionGuard min_version="21.0.3">
  <NewFeature />
</VersionGuard>

Features

RevenueCat In-App Purchases

// Paywall
despia(`revenuecat://launchPaywall?external_id=${userId}&offering=default`);

// Direct purchase
despia(`revenuecat://purchase?external_id=${userId}&product=monthly_premium_ios`);

window.onRevenueCatPurchase() fires when the store confirms a transaction. Verify entitlement before unlocking (via your backend webhook, or by reading the store directly):

window.onRevenueCatPurchase = async () => {
  const { restoredData } = await despia('getpurchasehistory://', ['restoredData']);
  if (restoredData.some(p => p.isActive && p.entitlementId === 'premium')) unlockPremium();
};

In the browser, fall back to a RevenueCat Web Purchase Link.

Intro · Reference


Push Notifications

Permission and OneSignal registration happen automatically at launch. Link the device to your user on every authenticated load:

despia(`setonesignalplayerid://?user_id=${userId}`);

// Check permission
const { nativePushEnabled } = await despia('checkNativePushPermissions://', ['nativePushEnabled']);
if (!nativePushEnabled) despia('settingsapp://');

// Local scheduled notification
despia('sendlocalpushmsg://push.send?s=60&msg=Hello&!#Title&!#https://myapp.com');

Configure OneSignal with Native iOS and Native Android as platforms, then send remote pushes from your backend with the OneSignal REST API.

Intro · Reference


Identity Vault

Encrypted key-value storage backed by iCloud KV (iOS) and Android App Backup. Values survive uninstall and sync across a user's own devices. Set locked=true to require Face ID, Touch ID, or fingerprint on read.

// Write
await despia('setvault://?key=sessionToken&value=abc123&locked=true');

// Read (prompts biometric if locked)
const { sessionToken } = await despia('readvault://?key=sessionToken', ['sessionToken']);

readvault:// throws if the key doesn't exist. Wrap in try/catch.

Docs


OAuth Authentication

Opens a secure browser session (ASWebAuthenticationSession / Chrome Custom Tabs). A deeplink with the oauth/ prefix closes the session and returns to your WebView.

const redirectUri = isDespia
  ? 'https://yourapp.com/native-callback.html'
  : 'https://yourapp.com/auth/callback';

const authUrl = `https://provider.com/oauth/authorize?client_id=xxx&redirect_uri=${encodeURIComponent(redirectUri)}`;

if (isDespia) {
  despia(`oauth://?url=${encodeURIComponent(authUrl)}`);
} else {
  window.location.href = authUrl;
}

In public/native-callback.html (plain HTML, not a framework route, so the hash isn't stripped on navigation):

<script>
  var hash  = new URLSearchParams(window.location.hash.substring(1));
  var token = hash.get('access_token');
  if (token) window.location.href = '{yourscheme}://oauth/auth?access_token=' + encodeURIComponent(token);
</script>

Deeplink format: {yourscheme}://oauth/{path}?params. Without the oauth/ prefix the browser session stays open.

Docs


AppsFlyer Attribution

iOS today, Android soon. Enable in Despia > App > Settings > Integrations > AppsFlyer with your dev key.

// Attribution available on every launch
despia.appsFlyerAttribution
despia.appsFlyerReferrer
despia.appsFlyerUID

// After login
despia('appsflyer://set_user_id?customer_user_id=' + encodeURIComponent(userId));

// Log an event (af_-prefixed events map to Meta and TikTok automatically)
const values = { af_revenue: 9.99, af_currency: 'USD' };
despia('appsflyer://log_event?event_name=af_purchase&event_values=' + encodeURIComponent(JSON.stringify(values)));

Intro · Attribution


GPS Location

window.onLocationChange = (data) => {
  if (data.active) console.log(data.latitude, data.longitude);
};

// buffer in seconds, movement threshold in centimetres
despia('location://?buffer=60&movement=100');

const { locationSession } = await despia('stoplocation://', ['locationSession']);

Add &server=https://api.example.com/track to POST each point as it's recorded.

Docs


Apple Health (HealthKit)

iOS only. Gate behind isDespiaIOS. Permissions are requested on first call per identifier.

// Read
const { healthkitResponse } = await despia(
  'readhealthkit://HKQuantityTypeIdentifierStepCount?days=7',
  ['healthkitResponse']
);

// Write
despia('writehealthkit://HKQuantityTypeIdentifierBodyMass//74.5');

// Observe and POST to your backend on change
despia('healthkit://observe?types=HKQuantityTypeIdentifierStepCount&frequency=hourly&server=https://api.example.com/webhook');

Any HKQuantityTypeIdentifier, HKCategoryTypeIdentifier, HKWorkoutTypeIdentifier, or HKCharacteristicTypeIdentifier works.

Docs


File and Media Operations

Standard HTML file inputs route to native UI with events delivered back to the input:

<input type="file">                                       <!-- Action sheet -->
<input type="file" accept="image/*">                      <!-- Image gallery -->
<input type="file" accept="video/*">                      <!-- Video gallery -->
<input type="file" accept="image/*" capture="environment"><!-- Camera -->
despia('takescreenshot://');
despia('savethisimage://?url=https://example.com/image.jpg');
despia('file://https://example.com/document.pdf');
despia('shareapp://message?=Check%20this%20out&url=https://myapp.com');

File sharing · Camera roll


AdMob Inline Ads

Ads render as real DOM elements via Google's WebView API for Ads. Enable in Despia > App > Settings > AdMob, then use standard AdSense, Google Publisher Tag, or IMA tags. No SDK calls from web.

Inline ads · Rewarded


Web Payment Request API

Apple Pay and Google Pay work through the standard Payment Request API with no Despia-specific calls.

const request = new PaymentRequest(
  [{ supportedMethods: 'https://apple.com/apple-pay' }],
  { total: { label: 'Total', amount: { currency: 'USD', value: '9.99' } } }
);
await (await request.show()).complete('success');

Docs


Local Server

Caches the web build on-device and serves it from http://localhost for offline launch. Updates are detected and swapped atomically on the next launch.

npm install --save-dev @despia/local
// vite.config.js (also Webpack, Rollup, Nuxt, SvelteKit, Astro, Remix, esbuild)
import { despiaLocalPlugin } from '@despia/local/vite';

export default {
  plugins: [despiaLocalPlugin({ outDir: 'dist', entryHtml: 'index.html' })],
};

Or run npx despia-local dist after any build. Deploy as normal.

Intro · Reference


Local CDN

Cache remote files on-device for offline playback and background downloads. Transfers use NSURLSession / WorkManager and continue when the app is closed, with Live Activity (iOS) or system tray (Android) progress.

// Called on download complete
window.contentServerChange = (item) => {
  // item.local_cdn, item.cdn, item.index, item.size, item.status, item.local_path
};

// Start a download. Do NOT await with a watch key.
despia(`localcdn://write?url=${remoteUrl}&filename=videos/clip.mp4&index=clip_1`);

// Query cache
const { cdnItems } = await despia('localcdn://query', ['cdnItems']);

Play cached media from the local_cdn URL. For uploads, POST to http://${window.location.host}/api/upload (Local Server only).

Intro · Reference


Web Storage APIs

The app runs on a real origin, so localStorage, IndexedDB, and Web Crypto work normally. For data that must survive uninstall or be locked behind biometrics, use Identity Vault.


Haptic Feedback

despia('lighthaptic://');   // Subtle
despia('heavyhaptic://');   // Strong
despia('successhaptic://'); // Success
despia('warninghaptic://'); // Warning
despia('errorhaptic://');   // Error

Docs


UI Controls and Styling

despia('spinneron://');
despia('spinneroff://');
despia('hidebars://on');                     // Hide status bar
despia('hidebars://off');
despia('statusbarcolor://{255, 255, 255}');  // RGB
despia('statusbartextcolor://{black}');      // black | white
despia('settingsapp://');                    // Open native app settings
despia('reset://');

Safe areas · App settings


App Information and Device Data

const { versionNumber, bundleNumber } = await despia('getappversion://', ['versionNumber', 'bundleNumber']);
const { uuid }             = await despia('get-uuid://',              ['uuid']);
const { storeLocation }    = await despia('getstorelocation://',      ['storeLocation']);
const { trackingDisabled } = await despia('user-disable-tracking://', ['trackingDisabled']);

Device indexing · Store location · App privacy


Clipboard

const { clipboarddata } = await despia('getclipboard://', ['clipboarddata']);

Docs


Contacts

const { contacts } = await despia('readcontacts://', ['contacts']);

Docs


Capability Reference

Core. Identity Vault, Face ID / Touch ID / fingerprint, background GPS, contacts, clipboard, haptics, native file system, image saving, background audio, local push, status bar controls, safe area CSS variables, device orientation, zoom lock, sleep lock, fullscreen, splash screen, iOS Home Widgets, Siri Shortcuts, native share, AirPrint, screen shield, PkPass for mobile wallets.

SDK bridges. RevenueCat, OneSignal, AppsFlyer, AdMob, HealthKit.

Infrastructure. ATT compliance, vendor ID, store location, jailbreak detection, App Clips, Share Extensions, Home Widget configuration.

Web interception. <input type="file"> routes to the native action sheet; capture opens the camera; accept filters to media gallery. Deeplinks and HTTPS deeplinks are handled natively.


Safe Area

Top and bottom safe area insets are exposed as CSS custom properties:

.header { padding-top: var(--safe-area-top); }
.footer { padding-bottom: var(--safe-area-bottom); }

Left and right insets are not exposed.

Docs


Extending the Runtime

Intercept any custom scheme in WebViewController.swift (iOS) or MainActivity.java (Android), run native code, write the result back as a window variable. The SDK resolves it the same way as built-in schemes.

// iOS
if requestURL.absoluteString.hasPrefix("mycustom://") {
    webView.evaluateJavaScript("window.myResult = '\(runMyNativeCode())';")
    decisionHandler(.cancel)
    return
}
// Android
if (url.startsWith("mycustom://")) {
    webView.evaluateJavascript("window.myResult = '" + runMyNativeCode() + "';", null);
    return true;
}
// Web
const { myResult } = await despia('mycustom://', ['myResult']);

Full Xcode and Android Studio project export is available for custom native code.


Web Native vs React Native

This SDK is for web-native apps (React, Vue, Angular, Svelte, Next.js, Vite, Nuxt, vanilla JS) running inside the Despia runtime. It is not for React Native, Expo, or native mobile development.


Publishing

iOS and Android store deployment runs from the web editor. Cloud Mac Mini infrastructure handles code signing, provisioning, and submission.

iOS · Android


MCP Server

Point your AI assistant at the Despia MCP for the full despia-native API.

Install in Cursor Install in VS Code

For web builders (Lovable, Bolt, v0), paste: https://setup.despia.com/mcp.

Setup guide


How It Works

The SDK is a thin wrapper over a setter-based protocol bridge. Calling despia() assigns the scheme string to window.despia, which the native layer intercepts:

// When you call:
despia('lighthaptic://');

// the SDK does:
window.despia = 'lighthaptic://';

iOS intercepts the assignment in WebViewController.swift; Android intercepts it in MainActivity.java. Results come back as named window variables, which the SDK resolves as a promise via the optional watch array. For long-running work (downloads, purchases, biometric prompts), the native layer calls back via global functions like window.onRevenueCatPurchase or window.contentServerChange instead.

No dependencies, no initialization, no lifecycle to manage.


Support

npm@despia.com

Popular repositories Loading

  1. despia despia Public

    TypeScript 18 9

  2. openmind openmind Public

    3

  3. base44-native-boilerplate base44-native-boilerplate Public

    Base44 App: Despia Native

    JavaScript 2 1

  4. base44-revenuecat base44-revenuecat Public

    In-app purchases and subscriptions for Base44 apps shipped natively with Despia. RevenueCat, StoreKit and Google Play Billing, with server-side verification and zero native code.

    JavaScript 2

  5. despia-native despia-native Public

    JavaScript 1 1

  6. docs docs Public

    MDX 1