Overview
Apps built with App Studio load your website inside a fast native shell and add a JavaScript bridge, window.tekservix, so your pages can use native features: share sheet, haptics, QR and document scanners, biometrics, secure storage, push notifications, in-app purchases, background location and more.
Quick start
- Create the app. In App Studio choose Website to App (pay once per platform) or Native App (monthly plan with native features), then paste your website address. We read its name, colours, icon and menu.
- Design it. Set the icon and splash screen, tabs or side menu, colours, and which links stay inside the app. The phone preview updates as you type.
- Try it free. Build a free Android test app (APK) and install it from the QR code. Website-to-App trials last 7 days; the test app stops opening when the trial ends.
- Go live. Buy the platforms you need or choose a Native plan, then build the store-ready Android app (APK + AAB) and the iOS app, signed in your own Apple account and uploaded to TestFlight.
Builds, trial and plans
| Website to App | Native App | |
|---|---|---|
| Payment | One-time per platform: Android, iOS or both | Monthly or yearly plan (Starter, Pro, Agency) |
| Free trial | 7 days of Android test builds (watermarked) | Android test builds while you set up |
| Store builds | For the platforms you own; free updates for a year, then a small fee per rebuild | Unlimited, iOS and Android |
| Native features | Push, QR scanner, rate prompt, AdMob, analytics | Plus offline mode, dark mode, Face ID, in-app purchases, background tasks, NFC, document scanner |
iOS apps have no free trial. Builds that didn’t finish (failed, cancelled or never started) can be deleted from Builds and are removed automatically after 3 days.
Detect the app
Inside the app, your pages get three signals:
- The
<html>element has the classestekservix-appandtekservix-android. - The user agent contains
TekservixAppplus the suffix you set in App Studio. window.tekservix.isAppistrueonce the bridge is ready.
/* Hide your "Download our app" banner inside the app */
.tekservix-app .get-the-app { display: none; }
// JavaScript
const inApp = /TekservixApp/.test(navigator.userAgent);
window.addEventListener('tekservix', e => {
if (e.detail.event === 'ready') console.log('bridge ready');
});
JavaScript bridge
Every call returns a Promise. Calls are only accepted from the domains you list in App Studio (Links → domains inside the app). If a feature isn't switched on for the app, the Promise rejects with a message saying so.
try {
const info = await tekservix.device.info();
console.log(info.model, info.language);
} catch (err) {
console.warn(err.message); // e.g. "'qr' is not enabled in this app…"
}
// Generic form, same as the helpers below
await tekservix.call('haptic', { type: 'success' });
Events
Listen with tekservix.on(name, fn) (returns an unsubscribe function) or the tekservix DOM event.
| Event | When | Data |
|---|---|---|
ready | The bridge is loaded on a page | { platform } |
push.received | A push arrives while the app is open | { title, body, url, data } |
purchases.updated | A purchase finished or changed | array of purchases |
location | Background location fix | { latitude, longitude, accuracy, … } |
nfc.tag | An NFC tag was read | { id, techs, records } |
qr | Floating button scan that isn't a link | { text, format } |
Native UI
| Call | What it does |
|---|---|
tekservix.share({ title, text, url }) | Native share sheet. Share a file with { file: base64, filename, mime }. |
tekservix.toast(text, long) | Short native message at the bottom. |
tekservix.banner(text, { position, bg, fg, duration }) | Banner at the top or bottom that hides itself. |
tekservix.haptic(type) | light, medium, heavy, success, warning, error, selection. |
tekservix.vibrate(ms | pattern[]) | Vibrate for a time, or a pattern like [0, 200, 100, 200]. |
tekservix.statusBar.set({ color, style, hidden }) | Status bar colour, light/dark icons, hide/show. |
tekservix.navigationBar.set({ color }) | Bottom system bar colour. |
tekservix.screen.keepOn(true) | Stop the screen from sleeping (recipes, tickets, maps). |
tekservix.screen.brightness(1) | Full brightness for a QR ticket; -1 restores. |
tekservix.screen.fullscreen(true) | Hide system bars (games, video). |
tekservix.screen.orientation('landscape') | portrait, landscape or auto. |
tekservix.datePicker({ mode, value, min, max }) | Native date/time picker. mode: date, time, datetime. Resolves to an ISO string. |
tekservix.print() | Android print dialog (also replaces window.print()). |
tekservix.screenshot({ save, share, scale }) | Image of the page as a data URL; optionally saves or shares it. |
tekservix.page.loader(true) | Show/hide the loading bar. |
tekservix.app.rate() | Google Play review prompt (or opens your store page). |
Device
| Call | Needs | Result |
|---|---|---|
tekservix.device.info() | — | { platform, osVersion, sdk, manufacturer, model, language, timezone, darkMode, width, height, deviceId, online } |
tekservix.app.info() | — | { name, package, version, build, features } |
tekservix.scanner.qr({ formats, prompt, front, torch }) | QR scanner | { text, format } |
tekservix.scanner.document({ pages, gallery, pdf }) | Document scanner | { pages: [dataUrl], pdf: dataUrl, pageCount } |
tekservix.nfc.read({ timeout }) / nfc.stop() | NFC reader | { id, techs, records: [{ type, text, uri, payload }] } |
tekservix.location.current({ highAccuracy }) | Location | { latitude, longitude, accuracy, altitude, speed, heading, timestamp } |
tekservix.contacts.pick() | — | { name, phone } — no contacts permission needed |
tekservix.calendar.add({ title, description, location, start, end, allDay, timezone }) | — | Opens the calendar's “new event” screen |
tekservix.clipboard.copy(text) / read() | — | — |
tekservix.open.external(url) / inAppBrowser(url) / app(url) | — | Browser, in-app browser tab, or another app (intent:, whatsapp:…) |
tekservix.app.openSettings() | — | The app's system settings (permissions) |
tekservix.audio.background({ title, text }) / audio.stop() | Background audio | Keeps your web audio playing with the screen off |
tekservix.download({ data, filename, mime }) | — | Saves base64 data to Downloads |
Camera, microphone and the browser's navigator.geolocation work as on the web once you switch those permissions on in App Studio.
Storage & security
// Native storage (survives cache clears; good for settings)
await tekservix.storage.set('theme', 'dark');
const theme = await tekservix.storage.get('theme');
// Keystore-encrypted storage for tokens
await tekservix.secureStorage.set('refresh_token', token);
// Biometric unlock before reading the token
const { available } = await tekservix.biometric.available();
if (available) {
await tekservix.biometric.authenticate({ title: 'Sign in', subtitle: 'Use your fingerprint' });
const token = await tekservix.secureStorage.get('refresh_token');
}
const rooted = await tekservix.device.isRooted();
Push notifications
Push notifications run on your own Firebase Cloud Messaging or OneSignal project: you own the subscriber list and send from your console or your server. Choose the provider in App Studio → Push notifications, add your Firebase or OneSignal details and rebuild. In your pages:
await tekservix.push.permission(); // Android 13+ asks the user
tekservix.push.setUser(String(user.id)); // after sign-in; setUser(null) on sign-out
tekservix.push.subscribe('promotions'); // topics
const token = await tekservix.push.token(); // FCM token: save it on your server with the signed-in user
tekservix.on('push.token', e => saveToken(e.token)); // fires when Firebase issues a new token
tekservix.on('push.received', n => showInAppMessage(n.title, n.body));
A notification with a url in its data opens that page in the app when tapped. With OneSignal, push.setUser(id) sets the OneSignal external ID so you can target that user from OneSignal.
Sending notifications
Campaigns: Firebase console → Messaging → New campaign, or the OneSignal dashboard → Messages. Add a custom data key url to open a page.
Automatic alerts from your server (order shipped, new message) with the Firebase Admin SDK and the tokens your site saved:
// Node.js — npm install firebase-admin (service account from Firebase → Project settings → Service accounts)
import admin from 'firebase-admin';
admin.initializeApp({ credential: admin.credential.cert(serviceAccount) });
await admin.messaging().send({
token: user.pushToken,
notification: { title: 'Order shipped', body: 'Order #1042 is on its way' },
data: { url: 'https://yoursite.com/orders/1042' },
});
// Everyone subscribed to a topic (tekservix.push.subscribe('promotions'))
await admin.messaging().send({ topic: 'promotions', notification: { title: 'Weekend sale', body: '20% off everything' } });
OneSignal: call the OneSignal REST API from your server with your REST API key and include_aliases: { external_id: [userId] }. Keep server keys on your server — never put them in your website or app.
Analytics
tekservix.analytics.event('purchase', { value: 25000, currency: 'RWF' });
tekservix.analytics.setUser(String(user.id));
Events go to every analytics tool switched on for the app (Firebase Analytics, Meta App Events, AppsFlyer). Firebase also records a screen view for each page automatically.
Ads & purchases
// AdMob (units set in App Studio)
await tekservix.ads.showInterstitial();
const reward = await tekservix.ads.showRewarded(); // { type, amount }
tekservix.ads.hideBanner();
// Google Play Billing
const products = await tekservix.purchases.products({ ids: ['premium_monthly'], type: 'subs' });
const purchases = await tekservix.purchases.buy({ id: 'premium_monthly', type: 'subs', accountId: user.id });
// Send purchases[0].token to your server and verify it with the Google Play Developer API.
await tekservix.purchases.restore({ type: 'subs' });
await tekservix.purchases.consume({ token }); // one-time consumables
Google requires Play Billing for digital goods sold in Android apps; physical goods and services can keep using your normal web checkout.
Background location
For delivery and field-team apps. A notification shows while tracking runs. Each fix is POSTed as JSON to your URL:
await tekservix.location.startBackground({
url: 'https://yoursite.com/api/driver-location', // optional, defaults to App Studio
interval: 30, distance: 20,
data: { driver_id: 17 },
headers: { Authorization: 'Bearer ' + driverToken }
});
// your server receives:
{ "driver_id": 17, "latitude": -1.9441, "longitude": 30.0619, "accuracy": 8.5,
"speed": 6.2, "heading": 270, "altitude": 1567, "timestamp": 1760670000000,
"provider": "gps", "device_id": "…" }
await tekservix.location.stopBackground();
Deep links & App Links
Custom scheme: yourscheme://products/42 opens https://yoursite.com/products/42 in the app.
Android App Links make your normal website links open the app. Add your domains in App Studio → Deep links, make a release build, then publish the assetlinks.json shown there at https://yourdomain/.well-known/assetlinks.json. If Google Play signs your app, add the SHA-256 from Play Console → Setup → App integrity too.
Share into the app: switch it on and set a page such as https://yoursite.com/share?text={text}&url={url}.
Firebase set-up (push, Analytics, Crashlytics)
- Open Firebase console and create a project (free).
- Add an Android app with exactly your app's package name from App Studio.
- Download
google-services.jsonand upload it in App Studio → Push notifications. - For iOS push, upload your APNs key in Firebase → Project settings → Cloud Messaging.
- Rebuild the app.
OneSignal instead? Create a OneSignal app, connect your Firebase credentials there (OneSignal's guide), then paste your OneSignal App ID in App Studio. Your REST API key stays on your own server.
Google & social sign-in
Google doesn't allow its sign-in page inside embedded web views. Add a link rule for accounts\.google\.com that opens in the in-app browser tab, and have your sign-in redirect back to your site. Facebook and Apple sign-in work the same way. For native one-tap sign-in, order a custom integration.
iOS builds & TestFlight
iOS apps are compiled on cloud Macs and signed in your Apple Developer account, so the app is published under your name.
- In App Store Connect → Users and Access → Integrations, create a Team API key with the App Manager role and download the
.p8file. - In App Store Connect → Apps, create the app with the bundle ID shown in App Studio (iOS & App Store).
- Paste the Issuer ID and Key ID in App Studio and upload the
.p8file, then click Build iOS app.
Each build is uploaded to TestFlight automatically (about 10–30 minutes after it finishes, once Apple has processed it). From TestFlight you test on your iPhone and submit to App Review. The signed .ipa is also available to download.
Store-review tips
- Give the app native value: a tab bar or menu, push notifications and at least one device feature.
- Hide website-only parts in the app (cookie banners, “download our app”, desktop footers) with the hide-elements box.
- Provide a test account for reviewers if your app needs sign-in, and a privacy policy URL.
- Only switch on permissions your site really uses — the stores ask why you need each one.
- Digital subscriptions in the app must use in-app purchases on both stores.
Nothing matches your search. Try another word, or ask our team.