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"]
    }
  ]
}
Backward compatibility

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

FieldTypeStatusDescription
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:

FieldTypeDescription
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:

FieldTypeStatusDescription
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.

PermissionDescriptionNotes
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
Notifications require a license

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
Permitted content only

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:

  1. The container fetches the manifest from the domain (or update_url if specified).
  2. If app_version differs from the installed version, an update is detected.
  3. The new ZIP is downloaded and extracted, replacing the previous bundle.
  4. The update is applied silently — no user action required.
Versioning tip

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 valueResolved 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