Manifest Specification
The loadsites.app.manifest file describes your CWA app. It must be hosted at the
root of your domain as a JSON file.
File Location
The manifest must be accessible at:
https://<your-domain>/loadsites.app.manifest
The file must be valid JSON with a Content-Type of application/json
(recommended) or text/plain. CORS headers are required if the LoadSites app
fetches from a different origin.
Single-App Format
The simplest manifest describes a single app. All app fields are at the top level:
{
"loadsites_version": "1.0",
"app_author": "Jane Doe",
"license_key": "",
"app_name": "My App",
"app_description": "A simple CWA app",
"app_version": "1.0.0",
"app_icon": "https://example.com/icon-512.png",
"app_zip": "https://example.com/my-app.zip",
"app_entry": "index.html",
"permissions": ["haptics", "storage"]
}
When no apps array is present, the container treats the manifest as a single-app
manifest with an implicit app_id of "default".
Multi-App Format
A domain can offer multiple apps using the apps array. Users choose which apps
to install during the setup flow:
{
"loadsites_version": "1.0",
"app_author": "Acme Corp",
"license_key": "LS-BASIC-xxxx",
"apps": [
{
"app_id": "chat",
"app_name": "Acme Chat",
"app_description": "Team messaging",
"app_version": "2.1.0",
"app_icon": "https://acme.com/icons/chat.png",
"app_zip": "https://acme.com/apps/chat.zip",
"app_entry": "index.html",
"permissions": ["notifications", "haptics", "camera", "storage"]
},
{
"app_id": "calendar",
"app_name": "Acme Calendar",
"app_description": "Shared calendar and scheduling",
"app_version": "1.3.0",
"app_icon": "https://acme.com/icons/calendar.png",
"app_zip": "https://acme.com/apps/calendar.zip",
"app_entry": "index.html",
"permissions": ["notifications", "haptics", "storage"]
}
]
}
When the apps array is present, top-level single-app fields
(app_name, app_zip, etc.) are ignored. You can include both for
backward compatibility with older container versions, but the apps array
takes precedence.
Top-Level Fields
| Field | Type | Status | Description |
|---|---|---|---|
loadsites_version |
string | Required | CWA spec version. Currently "1.0". |
app_author |
string | Required | Author or organization name. |
license_key |
string | Required | LoadSites license key. Empty string "" for free tier. |
min_container_version |
string | Optional | Minimum LoadSites container version required (e.g., "1.2.0"). |
update_url |
string | Optional | Alternative URL to check for manifest updates. Defaults to the original fetch URL. |
apps |
ManifestApp[] | Optional | Array of app entries for multi-app manifests. If absent, single-app fields are used. |
Single-App Fields
These fields are used when apps is absent. They are required for single-app
manifests:
| Field | Type | Description |
|---|---|---|
app_name |
string | Display name of the app (max 30 characters). |
app_description |
string | Short description shown during install. |
app_version |
string | Version string (e.g., "1.0.0"). Used for update detection. |
app_icon |
string (URL) | URL to the app icon. Recommended 512x512 PNG. |
app_zip |
string (URL) | URL to the ZIP bundle containing the app files. |
app_entry |
string | Entry file within the ZIP (e.g., "index.html"). |
permissions |
string[] | Array of permissions the app requires. See Permissions. |
ManifestApp Object
Each entry in the apps array must contain:
| Field | Type | Status | Description |
|---|---|---|---|
app_id |
string | Required | Unique identifier within this domain. Lowercase alphanumeric + hyphens, max 30 chars. (e.g., "chat", "admin-panel") |
app_name |
string | Required | Display name (max 30 characters). |
app_description |
string | Required | Short description shown in the app selector. |
app_version |
string | Required | Version string for update detection. |
app_icon |
string (URL) | Required | App icon URL. Recommended 512x512 PNG. |
app_zip |
string (URL) | Required | URL to the ZIP bundle. |
app_entry |
string | Required | Entry file within the ZIP. |
permissions |
string[] | Required | Permissions required by this specific app. |
Permissions
The permissions array declares which bridge APIs the app will use. The container
presents this list to the user during installation, and the user must accept before the app
is installed. Permissions are enforced at runtime — bridge calls for undeclared
permissions are rejected. This permission-gated model ensures that CWA apps cannot silently
access device capabilities, aligning with Apple App Store (Guideline 4.7.2) and Google Play
policies on user consent and data access.
| Permission | Description | Notes |
|---|---|---|
camera |
Access camera and photo library | |
microphone |
Record audio | |
geolocation |
Access GPS location | |
notifications |
Send push notifications | License Required |
haptics |
Vibration and haptic feedback | |
share |
Native share sheet | |
clipboard |
Read/write system clipboard | |
biometrics |
Fingerprint or face authentication | |
storage |
Persistent key-value storage | |
network |
Network connectivity status | |
device |
Device model, platform, OS info |
The notifications permission is the only one that requires a paid LoadSites
license (Basic tier or higher). All other permissions are free to use.
See Notifications for licensing details.
ZIP Bundle Structure
The ZIP file must contain only standard web assets. CWA bundles are rendered inside the
platform's native WebView (WKWebView / WebKit on iOS, Android WebView
on Android), so only content that runs within the WebView sandbox is permitted.
my-app.zip
├── index.html <-- app_entry points here
├── css/
│ └── style.css
├── js/
│ └── app.js
└── assets/
├── logo.png
└── data.json
- Maximum ZIP size: 50 MB
- The entry file (specified by
app_entry) must exist at the root of the archive - All relative paths in your HTML/CSS/JS will work as expected
- Do not include
node_modulesor build tooling — only production assets
ZIP bundles may only contain standard web assets: HTML, CSS, JavaScript, images, fonts, JSON, and SVG. No native executables, binaries, bytecode, shared libraries, or WebAssembly modules that access platform APIs are permitted. All JavaScript runs within the WebView's built-in JavaScript engine. This restriction ensures compliance with Apple App Store (Guideline 2.5.2) and Google Play policies regarding downloaded code.
Update Mechanism
LoadSites checks for updates each time the user opens an app:
- The container fetches the manifest from the domain (or
update_urlif specified). - If
app_versiondiffers from the installed version, an update is detected. - The new ZIP is downloaded and extracted, replacing the previous bundle.
- The update is applied silently — no user action required.
Use semantic versioning (e.g., "1.2.3") for your app_version.
The container performs a string comparison, so any change triggers an update.
URL Resolution
Relative URLs in app_icon and app_zip are resolved relative to the
manifest URL. For example, if the manifest is at
https://example.com/loadsites.app.manifest:
| Manifest value | Resolved URL |
|---|---|
"app.zip" |
https://example.com/app.zip |
"/assets/app.zip" |
https://example.com/assets/app.zip |
"https://cdn.example.com/app.zip" |
https://cdn.example.com/app.zip |
Validation Rules
loadsites_version,app_author, andlicense_keyare always required- Either top-level single-app fields OR the
appsarray must be present app_idmust match/^[a-z0-9][a-z0-9-]*$/and be at most 30 charactersapp_idvalues must be unique within a single manifest- All permission values must be from the valid permissions list
app_namemust be non-empty and at most 30 charactersapp_zipmust be a valid URL (absolute or relative)