Skip to content
Web to App

Turn your website into an Android app

Web to App is an OpenAlly mini-app that turns a website you run into an Android app, free on every plan. Paste the site's address: OpenAlly reads its name, colours and icon, then builds a signed APK to install or share — and an AAB for your own Google Play upload — on your Android phone or Mac. A build takes as little as 10 seconds, usually under a minute; the first build also creates your signing key.

  • Signed APK
  • AAB for your Play upload
  • From about 10 seconds
  • Free on every plan

Builds on

  • Android — supported
  • Mac — supported

Not on iPhone.

A shop owner at a sunlit counter smiles at her phone while a small glowing assistant carries her website's app icon from the laptop to the phone.
Try it

Paste your site. Watch it become an app.

Type an address and follow the steps a real build takes: OpenAlly reads the site, prepares the signing key and the icons, then builds, signs and checks the APK and, once your key is backed up, the AAB. This demo runs in the page; nothing is sent anywhere.

A fixed https address you run. A path is fine; a ? or # part is not.

A real build takes as little as 10 seconds, usually under a minute; the first build also creates your signing key.

  1. Read your site, done
  2. Prepare the build, done
  3. APK, done
  4. AAB, done
  5. Ready, done

Finished

Release details

App name
Rekha Pottery
Welcome colour
#60A5FA
Icon
Your site's icon, or one you upload or create with AI
Version
1.0.0 · code 1
Signing key
Backed up
Status-bar icons
Light
Welcome screen

Rekha Pottery

Made with OpenAlly

On the home screen

Rekha Pottery

In OpenAlly these come from your site itself — its name, colours and icon — and you can change any of them before you build.

Your files

The APK

Ready

Install it or share it

rekha-pottery-1.0.0-1.apk

Package id
ai.openally.app.a58yjxke7pbbs5py4sw8enj704g
Version
1.0.0 (1)
Signed
With this app's own key

On the build card

  • Save
  • Share
  • Open

The AAB

Ready

For your own Google Play upload

rekha-pottery-1.0.0-1.aab

Package id
ai.openally.app.a58yjxke7pbbs5py4sw8enj704g
Version
1.0.0 (1)
Signed
With this app's own key

On the build card

  • Save
  • Share
  • Open
How it works

Four steps, one sitting

The same four steps in the Web to App mini-app on your Android phone or Mac, or in a chat with your AI.

  1. Paste a link

    Paste the fixed https address of a site you run. A path is fine; a temporary tunnel or a link that carries a token is not.

  2. Name and icon

    OpenAlly brings your site's name, colours and icon with it. Change any of them, write a welcome line, or create an icon with AI.

  3. Build

    Build a signed APK, plus an AAB once your signing key is backed up. Building and signing stay on your Android phone or Mac.

  4. Save or share

    Save the APK and tap it to install, share it with anyone, or upload the AAB to your own Google Play listing.

From your site

It starts with what your site already says about itself

OpenAlly reads the details your site publishes for browsers and link previews, never the content of its pages, and treats each one as a suggestion you can change.

  • Your site gives
    Its name, as the site gives it to browsers and link previews, or its page title
    Your app gets
    The name under the home-screen icon, up to 30 characters
  • Your site gives
    A short description, up to 500 characters
    Your app gets
    The supporting line on the welcome screen, up to 160 characters
  • Your site gives
    Its theme and background colours
    Your app gets
    Your brand colour, the welcome background, and status-bar icons that read on it
  • Your site gives
    The icons it lists, its touch icon and its page icon
    Your app gets
    A launcher icon prepared in every shape Android launchers use
Your app's features

Choose what your app can do

Every switch lives in the app's Android setup. Try them here: the two lists show what the built app will ask for and what your page will be able to reach.

Look and feel

  • Welcome text

    A headline and a supporting line on the welcome screen while your site opens.

  • Home-screen icon

    Keep your site's icon, upload an image, or choose Create my icon with AI, using your connected image provider or Premium image credits.

  • Status-bar icons

    Light or dark, so they read on your colours.

  • Orientation

    Follow the phone, Portrait or Landscape.

A shop owner compares hand-painted app icon tiles while a small glowing assistant brushes a gold leaf highlight onto the sage icon on an easel.

Only you can switch on camera, microphone, location, notifications and clipboard reading, or choose Classic and new for the newer page features. Your AI can switch any of them off, never on.

Colour key

  • App and device
  • Screen and navigation
  • Location and permissions
  • Files, photos and sharing
  • Notifications and haptics

The experience

  • Screen and navigation

    Pull to refresh

    Let people pull down at the top of a page to reload it.

  • Files, photos and sharing

    Downloads

    Let the app save files the page offers, such as an invoice or a receipt.

  • Screen and navigation

    Play media without a tap

    Let video and audio start on their own. Off means the person taps play first.

  • Notifications and haptics

    Vibration and haptics

    Let the page make the phone buzz on a tap. Off removes the vibration permission, and taps stay silent.

  • Files, photos and sharing

    Text selection and copying

    Let people select text on the page and copy it. Off also stops the page writing to the clipboard.

Links to other websites

Choose where links outside your website open.

What the app may use

  • Files, photos and sharing

    Camera

    For taking a photo or scanning a code from inside the app.

    Only you can switch this on

  • Location and permissions

    Microphone

    For recording audio or taking voice input from inside the app.

    Only you can switch this on

  • Location and permissions

    Location

    For finding where the person is, such as filling in a delivery address.

    Only you can switch this on

  • Notifications and haptics

    Notifications

    For the app to post a notification on the phone it is installed on.

    Only you can switch this on

Each switch does two things: it lets the page use that part of the phone, and it decides whether the built app asks for the matching permission at all. Anything left off is stripped out, so the install screen and the Play listing show only what you turned on. Notifications are ones your page posts on the phone.

Web-to-app bridge

Available to the page

What the page inside your app is allowed to ask the phone to do. Classic is the small set every app has had; Classic and new adds file pickers, location, the clipboard and screen control.

Only you can switch this on: Classic and new

These three are part of the newer surface, the App2Web SDK. Choose Classic and new above to use them.

  • Files, photos and sharing

    File and photo picking

    Let the page open the photo and file pickers and save a file to Downloads. The person always chooses the file, so this asks for no permission.

  • Files, photos and sharing

    Clipboard reading

    Let the page read what is on the clipboard, not just write to it. Android shows people a notice every time the page reads it.

    Only you can switch this on

  • Screen and navigation

    Screen control

    Let the page lock the orientation, keep the screen awake, restyle the status bar and handle the back button itself.

The built app will ask for

  • Internet access (App and device)
  • Network status (App and device)
  • Vibration (Notifications and haptics)

The page will be able to reach

  • App details (App and device)
  • Opening links (Screen and navigation)
  • Status bar style (Screen and navigation)
  • Share sheet (Files, photos and sharing)
  • Vibration (Notifications and haptics)
The files

Two signed files, and they are yours

Every build is signed with your app's own key, on your device. The APK installs on Android 7.0 and newer; the AAB is the file Google Play takes.

  • APK

    An installable Android app to save, share and try on a device. It installs on Android 7.0 and newer when you tap it.

  • AAB

    A Play Console upload bundle, built with an APK for testing the same release. It unlocks once your signing key is backed up.

A shop owner holds up her phone showing her shop app with a check mark, beside an open parcel holding a glowing app icon and a brass key tag.
A small glowing assistant hands a shop owner a brass key at her desk, the key that signs every later version of her app.

Back up the key once, and the AAB unlocks

Every Android app is signed, and the signature is what lets a phone accept a new version as an update. Your app's key is created on your device with its first build and lives there. Back it up once, to a file protected by a passphrase you choose, and the AAB unlocks — uploading one commits your Play listing to that key for good.

Lose a key with no backup and no later version of the app can be accepted as an update.

  • The package id is fixed

    Each app gets an id that starts with ai.openally.app when it is created. It never changes, which is what lets every later version install as an update.

  • Version codes only go up

    Each upload needs a higher version code than the last. Reusing the last one replaces a build you have not uploaded.

  • Every build is kept

    Each APK and AAB stays under Generated files, ready to save or share again, until you delete it.

  • Changing the address

    The next build opens the new address. Copies already installed keep the old one.

  • Deleting the app

    Removes its setup, builds and signing key from OpenAlly. Your website, installed copies and files you already saved or shared stay.

Your path to Google Play

Build your AAB here, then follow four steps in Play Console. Your publishing status lives there, and the upload is yours to make.

  1. Start with your developer account

    Open a Google Play developer account, then create your app in Play Console. Choose its name and language, and add a contact email.

  2. Give your app a storefront

    Give people a reason to install: a clear description, app icon, screenshots and support details that show what your app can do.

  3. Test the version you will ship

    Use a higher version code for each upload, meet Google's current target API level requirement, and complete the testing your account needs before production.

  4. Bring your app to people

    Choose your countries, pricing and release notes. Resolve the issues shown in Play Console, then send your changes for review.

Google Play's policy on apps with limited functionality does not allow "apps that only have limited functionality and content", so an app that only opens a website is judged on what that website does for the person using it.

A shop owner pins screenshots of her shop app to a cork board as she plans her own store listing, a sage app icon on the desk.
From chat

Or just ask your AI

In a chat, your AI can turn your website into an Android app with the Web to App skill: it checks the site, creates the app, builds it and hands you the files.

Try one of these

  • Website to Android app Turn my website into an Android app
  • APK from a link Make an APK for https://
  • Package a Builder app Package my Builder app for Android

What happens

  1. Checked the site

    It reads the name, colours and icon, and tells you in plain words if the address will not work.

  2. Created an app from your link

    With the name you gave, or the one your site suggests.

  3. Started an Android build

    An APK by default, and the AAB as well once your key is backed up.

  4. The build card

    Save, Share and Open, right in the chat.

Asking from WhatsApp or Telegram

The first build on an Android phone needs a small app component. In the app a download card appears in the chat; on a messaging channel your AI sends these steps instead:

  1. Open the OpenAlly app on your phone.
  2. Go to Hub, then Apps, then Web to App.
  3. Tap Download on the Android app shell card and wait for the small one-time download to finish.
  4. When it shows Installed, come back to this chat and ask me again.

On a Mac there is nothing to download.

Chat

Turn my website into an Android app: https://rekha-pottery.example.com

Checked the siterekha-pottery.example.com
Created an app from your linkRekha Pottery
Started an Android buildAPK
Rekha PotteryReady
rekha-pottery-1.0.0-1.apk
Version 1.0.0 (1)
SaveShareOpen
One message, start to finish: the checks, the build, and the card with your APK.
Curled up in a window seat, a shop owner asks for an app in a chat on her phone while a small glowing assistant unfolds the finished app icon.
From the App Builder

Package an app you built in OpenAlly

An App Builder app becomes an Android app the same way, once it has a fixed https address for the installed app to open.

  • Free

    Publish it from your phone

    Give it an address you keep: a name you claim on openally.shop or mywebonline.store, OpenAlly Link's reserved address, or your own domain, with open access so the installed app can reach it.

  • Premium

    Publish it to the cloud

    Premium plans host a static app at a fixed address, so it stays up while your phone is off. An app that answers on its own data routes publishes from your phone instead.

    See Premium plans

Addresses an installed app cannot rely on

  • Temporary tunnel links that change every time they restart
  • Addresses on your local network
  • Links that carry an access token
App2Web SDK · for developers

Your site can reach the phone

window.OpenAllyApp2Web — SDK 1.0.0, 51 methods across 16 namespaces, 9 event streams. Once the app's owner sets its Web-to-app bridge to Classic and new, the app injects it at document start, top frame only; nothing to install or import.

Five rules, in the order they matter

  1. Feature-detect, always. supports(cap) is a runtime answer: the same page in the same app can get two different sets on two phones. Write the fallback first.
  2. await, and branch on error.code. Never on error.message. Narrow with isError(e).
  3. A capability is switched on when the app is built, by its owner. A missing one is a sentence to show the owner, not something to retry.
  4. Top frame only. An iframe gets a surface whose every call rejects.
  5. await whenReady() before the first use. It resolves at once inside an app, and it never throws at a page that just wanted to ask.

Switching it on

In the app's Android setup, set Web-to-app bridge to Classic and new — the default is Classic only, the seven window.OpenAllyShell calls every app has had — then switch on what the page may use.

Built your app in the App Builder? It already writes these checks, and every app it scaffolds carries the types.

On your own website, check window.OpenAllyApp2Web after DOMContentLoaded: the app injects it before your scripts run, and an ordinary browser simply has none, so the same page keeps working there.

A small glowing assistant threads beads marked with camera, location, bell, share, clipboard and vibration shapes from a phone to a laptop.

App and device

Screen and navigation

Location and permissions

Files, photos and sharing

Notifications and haptics

Location and permissions

OpenAllyApp2Web.location

Where the person is, with their permission.

MethodWhat it doesSwitched on byAndroid permission
getLocation(options?: GetLocationOptions): Promise<LocationFix>A fresh position, or a recent one within maxAgeMs. Pass precise: true for fine location. LocationLocation android.permission.ACCESS_COARSE_LOCATION
getLastKnown(options?: LastKnownOptions): Promise<LocationFix | null>The last position the phone knows, or null. Read timestampMs for its age. LocationLocation android.permission.ACCESS_COARSE_LOCATION

In code

Location, with a fallback
const sdk = window.OpenAllyApp2Web; // absent in an ordinary browser
if (sdk) await sdk.whenReady();

if (sdk && sdk.available && sdk.supports("location")) {
  let status = await sdk.permissions.check("location");
  if (status.state !== "granted" && status.canAsk) {
    status = await sdk.permissions.request("location"); // getLocation never asks by itself
  }
  if (status.state === "granted") {
    try {
      const fix = await sdk.location.getLocation({ timeoutMs: 8000 });
      showNearestStore(fix.latitude, fix.longitude);
    } catch (e) {
      askForPostcode(); // e.code says why, e.g. "E_TIMEOUT"
    }
  } else {
    askForPostcode(); // status.remedy is written for the app's owner
  }
} else {
  askForPostcode();
}

What it doesn't do, by design

  • No device identifier of any kind: no serial, no advertising id, no fingerprint.
  • No file paths or content addresses. A picked file is a handle plus its details.
  • No app.exit and no navigation.canOpen: a page cannot close the app or probe which other apps are installed.
  • No live battery push. The battery event is a check every 30 s while the app is in front of the person.
  • No web push, no background work, no contacts, SMS, calendar, Bluetooth, NFC or biometrics.
Events, errors and limits

Events

OpenAllyApp2Web.on(type, handler) returns a function that stops it. A page can listen to 8 event types at once.

EventSwitched on byDeliveryAt most everyCurrent value on subscribe
lifecycleAlways onEvery eventNoneYes
networkAlways onLatest value wins250 msYes
batteryAlways onLatest value wins30 sYes
insetsAlways onOnce it settles50 msYes
keyboardAlways onOnce it settles50 msYes
orientationAlways onOnly when it changes100 msYes
colorSchemeAlways onOnly when it changes100 msYes
locationLocationAt the interval you pass to location.watch({ minIntervalMs, minDistanceM }, onFix)NoneNo
notificationNotificationsEvery eventNoneNo

Errors

Every failure is a thrown error with a code. Narrow it with OpenAllyApp2Web.isError(e), then branch on e.code. Two things are values, never errors: a permission check that says no, and a picker the person dismissed.

CodeWhat it meansTrying again can help
E_UNAVAILABLENo host at all: an ordinary browser, or a shell that injected nothing.No
E_DETACHEDThe app's page was closed or replaced while the call was running.Yes
E_FRAME_UNTRUSTEDA frame that is not the trusted top frame tried to call.No
E_SUBFRAME_UNSUPPORTEDA same-origin sub-frame's own port. Refused in v1.No
E_UNSUPPORTED_METHODThis host does not implement the method — usually an older app shell.No
E_FEATURE_DISABLEDThe capability was not switched on when the app was built.No
E_PERMISSION_NOT_DECLAREDThe app was built without that permission, so it can never be granted.No
E_PERMISSION_DENIEDThe permission has not been given: not asked yet, or the person said no this time.Yes
E_PERMISSION_BLOCKEDThe person said no permanently, or policy forbids asking.No
E_CANCELLEDThe person dismissed a system UI. Only where cancellation is not a value.No
E_INVALID_ARGAn argument was missing, the wrong type, or out of range.No
E_TOO_LARGEA payload or read exceeded its documented ceiling.No
E_TIMEOUTThe call did not settle in time.Yes
E_POLICY_REFUSEDThe SDK or the host refused on policy grounds (e.g. too many subscriptions).No
E_BUSYA single-flight slot is occupied — a picker is already open.Yes
E_ABANDONEDThe document was replaced, or the process died, before the call settled.Yes
E_IOA read or write failed.Yes
E_INTERNALAn unexpected host-side fault. Carries no detail in a release build.No

Limits

Event types a page can listen to at once
8
Largest chunk per file read
512 KiB
Largest file read in one go
4 MiB
Most items one pick returns
20
Largest thumbnail edge
1024 px
Time a call has to settle
20 s
Time a picker or dialog can stay open
3 min
Time to answer a back press
300 ms
Two back presses within this always leave
600 ms
Battery level rounding
5%
Free storage rounding
64 MiB
Every method in one table51
MethodWhat it doesSwitched on byAndroid permission
app.getInfogetInfo(): Promise<AppInfo> The app's own name, version, version code, package id and build.Always onNone
app.getCapabilitiesgetCapabilities(): Promise<CapabilitiesInfo> Which capabilities this build answers, plus a cached permission snapshot for greying out a button.Always onNone
device.getInfogetInfo(): Promise<DeviceInfo> Model, maker, brand and Android version. No identifier of any kind.Always onNone
device.getLocalegetLocale(): Promise<LocaleInfo> Preferred languages, time zone, UTC offset and the 12- or 24-hour preference.Always onNone
ui.getInsetsgetInsets(): Promise<Insets> Safe-area insets in dp, for padding around the camera cut-out and the gesture bar.Always onNone
ui.getOrientationgetOrientation(): Promise<OrientationInfo> Portrait or landscape, right now.Always onNone
ui.getMetricsgetMetrics(): Promise<ScreenMetrics> Viewport size in dp, pixel density, orientation and colour scheme in one read.Always onNone
ui.getKeyboardgetKeyboard(): Promise<KeyboardState> Whether the on-screen keyboard is up, and how much of the viewport it covers.Always onNone
ui.getColorSchemegetColorScheme(): Promise<ColorSchemeInfo> Light or dark, as the person has set the phone.Always onNone
ui.setStatusBarsetStatusBar(options: StatusBarOptions): Promise<UiWriteResult> Restyle the status bar. It resets when the page is replaced.Screen controlNone
ui.lockOrientationlockOrientation(options: LockOrientationOptions): Promise<UiWriteResult> Pin the rotation, or hand it back to the app's setting. Released when the page is replaced.Screen controlNone
ui.setKeepAwakesetKeepAwake(options: KeepAwakeOptions): Promise<UiWriteResult> Keep the screen on. Dropped when the page is replaced.Screen controlNone
haptics.vibratevibrate(options?: VibrateOptions): Promise<VibrateResult> One of five feedback kinds: light, medium, heavy, success or error.Vibration and hapticsVibration android.permission.VIBRATE
navigation.openExternalopenExternal(options: OpenExternalOptions): Promise<OpenExternalResult> Hand a link to the phone, and learn whether anything opened it.Always onNone
navigation.openInAppopenInApp(options: OpenInAppOptions): Promise<OpenExternalResult> Open a web page in a browser sheet over the app, where the phone has one, whatever the Links to other websites setting says. Pass toolbarColor to tint it.Always onNone
navigation.setBackHandlersetBackHandler(handler: BackHandler | null): void Take over the back button: return true when your page handled the press, or pass null to give it back. Answer within 300 ms.Screen controlNone
location.getLocationgetLocation(options?: GetLocationOptions): Promise<LocationFix> A fresh position, or a recent one within maxAgeMs. Pass precise: true for fine location.LocationLocation android.permission.ACCESS_COARSE_LOCATION
location.getLastKnowngetLastKnown(options?: LastKnownOptions): Promise<LocationFix | null> The last position the phone knows, or null. Read timestampMs for its age.LocationLocation android.permission.ACCESS_COARSE_LOCATION
permissions.checkcheck(name: PermissionName): Promise<PermissionStatus> Where a permission stands: granted, denied, blocked or unavailable. It never throws for a refusal.Always onNone
permissions.requestrequest(name: PermissionName, options?: PermissionRequestOptions): Promise<PermissionStatus> Ask with the system dialog, at most once per capability per app launch.Always onNone
permissions.openSettingsopenSettings(): Promise<OpenSettingsResult> Open this app's settings page, where a person can change a blocked permission.Always onNone
media.pickImagespickImages(options?: PickImagesOptions): Promise<PickResult> The system photo picker. No permission needed: the person chooses what the page sees.File and photo pickingNone
media.captureImagecaptureImage(options?: CaptureImageOptions): Promise<PickResult> Take one photo with the camera.CameraCamera android.permission.CAMERA
media.getThumbnailgetThumbnail(options: ThumbnailOptions): Promise<ThumbnailResult> A display-sized data URL for a picked photo, so a full-size photo never has to load.File and photo pickingNone
files.pickFilespickFiles(options?: PickFilesOptions): Promise<PickResult> The system file picker. Returns handles and file details, never paths.File and photo pickingNone
files.readChunkreadChunk(options: ReadChunkOptions): Promise<ReadChunkResult> Read part of a picked file as base64, up to 512 KiB a call, until eof.File and photo pickingNone
files.readAsDataUrlreadAsDataUrl(options: ReadAsDataUrlOptions): Promise<DataUrlResult> Read a whole file as a data URL, up to 4 MiB.File and photo pickingNone
files.saveToDownloadssaveToDownloads(options: SaveToDownloadsOptions): Promise<SaveToDownloadsResult> Save a file to Downloads, or through a save dialog on older phones. Tells you which.File and photo pickingNone
files.releaserelease(options: ReleaseOptions): Promise<ReleaseResult> Let go of a file handle early. Handles also end with the page.File and photo pickingNone
share.texttext(options: ShareTextOptions): Promise<ShareResult> Open the system share sheet with text, a title or a link.Always onNone
share.filefile(options: ShareFileOptions): Promise<ShareResult> Share a picked file through the system share sheet.Always onNone
clipboard.writewrite(options: ClipboardWriteOptions): Promise<ClipboardWriteResult> Put text on the clipboard.Text selection and copyingNone
clipboard.hasTexthasText(): Promise<ClipboardHasTextResult> Whether the clipboard holds text, so a paste button can show as disabled.Text selection and copyingNone
clipboard.readread(): Promise<ClipboardReadResult> Read the text on the clipboard. Android shows the person a notice when a page reads it.Clipboard readingNone
notifications.notifynotify(options: NotifyOptions): Promise<NotifyResult> Post a notification on the phone. Reusing an id replaces the earlier one.NotificationsNotifications android.permission.POST_NOTIFICATIONS
notifications.cancelcancel(options: CancelNotificationOptions): Promise<CancelNotificationResult> Take a notification back down.NotificationsNotifications android.permission.POST_NOTIFICATIONS
network.getStatusgetStatus(): Promise<NetworkStatus> Online or not, the kind of connection, and whether it is metered.Always onNone
battery.getStatusgetStatus(): Promise<BatteryStatus> Battery level, rounded to 5%, and whether it is charging.Always onNone
storage.getSpacegetSpace(): Promise<StorageSpace> Free and total storage, rounded down to 64 MiB steps.Always onNone
lifecycle.getStategetState(): Promise<LifecycleStatus> Whether the app is active, inactive or in the background, and what it was before.Always onNone
app.getInfoSyncgetInfoSync(): AppInfo | null The same answer as getInfo(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
device.getInfoSyncgetInfoSync(): DeviceInfo | null The same answer as getInfo(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
ui.getInsetsSyncgetInsetsSync(): Insets | null The same answer as getInsets(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
ui.getOrientationSyncgetOrientationSync(): OrientationInfo | null The same answer as getOrientation(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
ui.getMetricsSyncgetMetricsSync(): ScreenMetrics | null The same answer as getMetrics(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
ui.getKeyboardSyncgetKeyboardSync(): KeyboardState | null The same answer as getKeyboard(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
ui.getColorSchemeSyncgetColorSchemeSync(): ColorSchemeInfo | null The same answer as getColorScheme(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
network.getStatusSyncgetStatusSync(): NetworkStatus | null The same answer as getStatus(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
battery.getStatusSyncgetStatusSync(): BatteryStatus | null The same answer as getStatus(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
storage.getSpaceSyncgetSpaceSync(): StorageSpace | null The same answer as getSpace(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
lifecycle.getStateSyncgetStateSync(): LifecycleStatus | null The same answer as getState(), at once, from a snapshot; null where the phone cannot answer synchronously.Always onNone
Where it runs

Build on Android or Mac. Run on Android.

Web to App builds on your Android phone and in the Mac app. The apps it makes run on Android 7.0 and newer.

  • Android — supported
  • iPhone — not available
  • Mac — supported
  • On your Android phone

    The first build downloads a small one-time app component, under 1 MB. After that everything happens on the phone, signing included.

  • On your Mac

    The Mac app carries everything it needs, so there is nothing to download before your first build.

  • The apps it makes

    Android 7.0 and newer, with your name, colours and icon, and a small Made with OpenAlly line on the welcome screen.

Questions

Web to App, answered

How long does a build take?

As little as 10 seconds, usually under a minute. The first build also creates your app's signing key, and the first build on an Android phone downloads a small one-time app component.

What do I get from a build?

A signed APK you can install on Android 7.0 and newer or share with anyone and, once your signing key is backed up, an AAB, the file Google Play takes, for your own Play Console upload. Files are named after your app and version, like rekha-pottery-1.0.0-1.apk.

Does OpenAlly publish my app or install it for me?

No. OpenAlly builds and signs the files and hands them to you. You install the APK yourself by tapping it in Downloads, and you upload the AAB to your own listing in Google Play Console.

Why does the AAB need a key backup?

Uploading an AAB ties your Play listing to your app's signing key for good, and that key lives only on your device. So OpenAlly asks you to back it up once, to a file protected by a passphrase you choose, before it builds an AAB. Lose a key with no backup and no later version can be accepted as an update.

Which web addresses work?

A fixed https address you run, with or without a path, such as https://rekha-pottery.example.com/shop. Addresses with a port, an IP address, a username and password, a ? or # part, a local-network name or a temporary tunnel are refused, because the app keeps opening that address for as long as it is installed.

Does the app work offline?

It opens your live site, so it needs a connection. Without one it shows an offline screen with a Retry button, and reloads by itself when the connection comes back.

Can I remove the Made with OpenAlly line?

No. Every app made with Web to App shows a small Made with OpenAlly line on its welcome screen while your site loads. Your name, colours and icon are everywhere else.

Can I choose my own package name?

No. OpenAlly gives each app a package id that starts with ai.openally.app when the app is created, and it stays the same for the life of the app. That is what lets every later version install as an update.

Is Web to App a Premium feature?

No. Web to App is free on every plan. Premium helps around it: it can host an App Builder app at a fixed address in the cloud, and its image credits can draw your app's icon with AI.

Can the app use the camera, location or notifications?

Yes, when you switch them on. Camera, microphone, location and notifications start off, and each switch also decides whether the built app asks for that permission at all. Only you can switch them on; your AI can switch them off. Notifications are ones your page posts on the phone.

Does it work on iPhone?

Web to App builds on your Android phone or your Mac, and the apps it makes run on Android 7.0 and newer. It does not make iPhone apps.

Can my website's own code use the phone?

Yes. With the App2Web SDK a page inside your app can pick photos, save to Downloads, read the location, share, post notifications and more: 51 methods, each capability switched on by you. The App2Web SDK section of the Web to App page lists every method.

One more thing

Put your AI to work. Keep it yours.

Use it for the daily admin, the business operation, the website, or the creative idea. Then choose the model for each job and keep your agents, data, and workflows under your control.

Take the same work with you

Start in your hand, continue at your desk. Your account, agents, chats, and business records remain one body of work.

Live

Android · Google Play

Start where the day happens.

Run everyday work from your phone with the official Google Play install and the models you choose.

Your account, agents, chats, and work continue between Android and Mac.
Live · 1.0.2

Mac · Apple silicon

Give the same work more room.

Continue on a wider canvas with the Mac interface built natively for Apple silicon.

Direct, Developer ID–signed download. Not a Mac App Store listing.

OpenAlly for iPhoneComing soon

28 apps · 39 skills · 8 built-in tools

All install options
Work stored on deviceBring your own brainFree to start

Crash diagnostics exclude your conversation content.

Bring your own model. Keep control of your data. Cancel the trust issues.