Capacitor Plugin Configuration

Every configuration option for the DeployYourApp Capacitor plugin, with types, defaults, and a full example.


Complete reference for the plugins.DeployYourApp block in your Capacitor config, plus the settings you can change at runtime.

Where configuration lives

The plugin reads its configuration from the Capacitor config file — capacitor.config.json, capacitor.config.js, or capacitor.config.ts — under plugins.DeployYourApp. Native code reads it at plugin load, so changing it requires a rebuild of the native app, not just a new web bundle.

{
  "plugins": {
    "DeployYourApp": {
      "appId": "com.yourcompany.yourapp",
      "channel": "production"
    }
  }
}

Options

Option Type Default Description
appId string required Your app ID from the DeployYourApp dashboard. When unset, falls back to the iOS bundle identifier or the Android package name and logs a warning; update checks then only match if that identifier is your app ID.
updateUrl string https://api.deployyour.app Update server base URL. The plugin appends /api/update — do not include a path.
statsUrl string https://api.deployyour.app Analytics server base URL. The plugin appends /api/stats — do not include a path.
allowedDownloadHosts string[] ['storage.deployyour.app'] Extra hosts allowed to serve bundle downloads. The updateUrl and statsUrl hosts are always allowed, so this is only needed when bundles come from a different host, such as a CDN. Downloads are https-only (http from localhost alone); anything else rejects with INVALID_URL.
channel string production Update channel to check. A channel previously set with setChannel() takes precedence over this value.
autoUpdate boolean true Check on launch and every checkInterval seconds, download new bundles, and activate them according to applyMode.
applyMode string whenIdle When a downloaded update becomes active. One of whenIdle, immediate, onLaunch, background. See applyMode.
checkInterval number 600 Seconds between automatic update checks. 0 disables the repeating timer; the launch check still runs.
appReadyTimeout number 10000 Milliseconds a newly served bundle has to call notifyAppReady() before the plugin rolls back.
publicKey string required RSA public key (PEM, SPKI — -----BEGIN PUBLIC KEY-----) used to verify bundle signatures. Without it every download rejects with SIGNATURE_REQUIRED.
analyticsEnabled boolean true Collect and send analytics events. false stops all /api/stats traffic, including the plugin's own update_* events.
analyticsBatchSize number 20 Buffered events that trigger an immediate flush.
analyticsFlushInterval number 30 Seconds between automatic analytics flushes.
autoDeleteFailed boolean true Delete a bundle from disk when it is rolled back.
autoDeletePrevious boolean true Delete the previous bundle once the new one is confirmed by notifyAppReady().
resetWhenUpdate boolean true Reset to the built-in bundle when the native app version changes (for example a store update), and emit appVersionChange.
directUpdate string whenIdle Deprecated alias for applyMode. See directUpdate.

Full example

// capacitor.config.js
export default {
  appId: 'com.yourcompany.yourapp',
  appName: 'Your App',
  webDir: 'dist',
  plugins: {
    DeployYourApp: {
      // Identity
      appId: 'com.yourcompany.yourapp',
      channel: 'production',

      // Servers (only needed to target a non-default environment)
      updateUrl: 'https://api.deployyour.app',
      statsUrl: 'https://api.deployyour.app',

      // Update behaviour
      autoUpdate: true,
      applyMode: 'whenIdle',
      checkInterval: 600,
      appReadyTimeout: 10000,
      resetWhenUpdate: true,

      // Verification (required — there is no unsigned install path)
      publicKey: '-----BEGIN PUBLIC KEY-----\nMIICIjANBg...\n-----END PUBLIC KEY-----\n',

      // Analytics
      analyticsEnabled: true,
      analyticsBatchSize: 20,
      analyticsFlushInterval: 30,

      // Storage housekeeping
      autoDeleteFailed: true,
      autoDeletePrevious: true,
    },
  },
};

applyMode

applyMode decides when a downloaded bundle actually takes effect. It only governs the automatic flow — an explicit apply() call always activates the bundle immediately.

Value Behaviour
whenIdle Download in the background, stage the bundle, activate it on the next app launch. This is the default.
onLaunch Download in the background, hold the bundle as pending, activate it on the next app launch.
background Download only and emit downloadComplete. Nothing is activated until your app calls apply().
immediate Download, activate, and reload the webview during the current session.

whenIdle and onLaunch both activate on the next launch. They differ only in bookkeeping: whenIdle stages the bundle right away, while onLaunch holds it as pending and stages it during the next launch.

Three server-controlled fields on the update-check response override the local setting for that one update:

  • applyMode — takes precedence over the configured value.
  • mandatory: true — forces immediate, ignoring everything else.
  • delayUntil — an ISO 8601 timestamp, with either a Z or a numeric UTC offset. While it is in the future, the bundle is downloaded and held; it is staged by the first launch or update check after the timestamp passes. A timestamp the plugin cannot parse is treated as a deferral to the next launch — never as "apply now" — and logged.

An unrecognised applyMode string is treated as whenIdle.

directUpdate (deprecated)

directUpdate is the legacy name for applyMode. It is only consulted when applyMode is absent: "immediate" maps to immediate, and every other value maps to whenIdle. Use applyMode.

Runtime settings

Three values are stored on the device and outlive the config file. They are read by every update check.

Setting Set with Read with Storage
Channel setChannel({ channel }) getChannel() UserDefaults (iOS), dya_config preferences (Android), localStorage (web)
Custom device ID setCustomId({ customId }) not readable from JavaScript UserDefaults / dya_prefs / localStorage
Version override setVersionOverride({ version }) getVersionOverride() UserDefaults / dya_prefs / localStorage

Once setChannel() has run on a device, the stored channel wins over the channel value in the config file on every subsequent launch. To move a device back, call setChannel() again with the original name.

The version override replaces the reported bundle version in update checks, which is useful for testing targeting rules without shipping a bundle. Pass an empty string to clear it.

await DeployYourApp.setChannel({ channel: 'beta' });
await DeployYourApp.setVersionOverride({ version: '0.0.1' });
// ...
await DeployYourApp.setVersionOverride({ version: '' });

Keys

dya keys generate writes the RSA-4096 signing pair into .dya/ at your project's web root. One half belongs in this config:

File Config option Notes
.dya/dya-signing-public.pem publicKey Verifies the signature dya deploy produces with .dya/dya-signing-private.pem.

dya setup fills publicKey in for you when your config is capacitor.config.json. It does not copy whichever .pem it finds: the key is derived from the dya-signing-private.pem that dya deploy would sign with, and a dya-signing-public.pem on disk is used only when its fingerprint matches. If they disagree setup writes nothing to the Capacitor config at all and tells you which file to delete or restore — see Setup will not embed a key it cannot sign with. For a .ts or .js config nothing is written at all: setup prints the block to paste, because those are code and it will not rewrite them.

Keys generated by an older CLI at the project root, or inside src-capacitor/, are still found and used — see where keys are looked up.

Signature verification is mandatory and never fails open. Without publicKey, the plugin refuses every download with SIGNATURE_REQUIRED rather than proceeding on the checksum alone — the checksum arrives in the same response as the bundle URL, so it only proves the bytes were not corrupted in transit, not who produced them. A server that omits the signature is refused for the same reason.

There is no bundle encryption and no encryptionPrivateKey. Bundles are plain, signed ZIPs; what makes one trustworthy is the signature, and what keeps it installable is the asset policy. See Encryption and bundle signing.

The publicKey here is the one your app trusts

Whatever publicKey you build into a native release is what every copy of that release verifies against, forever. Deploying a bundle signed with any other key makes those installed apps reject that update and every update after it, and no server-side change can undo it — the apps in the field only trust the key they shipped with.

This is why dya keys generate refuses to mint a second keypair for a project that already has one, and why it stops outright — printing both fingerprints and marking the embedded one — when it finds two. dya setup runs that same check before it writes anything, since it is the command that decides which key ends up in the config. See One keypair per app.

It also protects the value already sitting in this file. Before merging its plugin config in, setup fingerprints the publicKey it would write against the one capacitor.config.json already holds, and a different key is not written on a y: it takes typing replace the signing key, and a bare Enter keeps the embedded key and stops setup. A clone of a project that has already shipped lands there by default — this file is committed while .dya/* (the private key) is not — so the check exists for the ordinary case, not the careless one. See Replacing an embedded signing key needs a typed phrase.

Turning off network traffic

analyticsEnabled: false stops all traffic to /api/stats, including the update lifecycle events the plugin records on its own. To stop contacting the update server as well, set autoUpdate: false and do not call checkForUpdate():

{
  "plugins": {
    "DeployYourApp": {
      "appId": "com.yourcompany.yourapp",
      "analyticsEnabled": false,
      "autoUpdate": false
    }
  }
}

What each endpoint receives is listed in SDK data collection.


Previous
Setup
Next
API Reference